Compare commits

...

66 Commits

Author SHA1 Message Date
Martin Michelsen a9dcd4b87e enforce stack limits when loading BB character data
Docker / Build (push) Has been cancelled
2025-08-06 21:23:30 -07:00
Martin Michelsen 5c84581978 add names in show-battle-params 2025-08-06 21:03:20 -07:00
Martin Michelsen ab38a58e39 mention address config in readme 2025-08-06 21:02:30 -07:00
Martin Michelsen d430112a94 support chat shell command for non-proxy clients 2025-07-27 14:18:48 -07:00
Martin Michelsen 0cf59f874d use remote_addr for SocketChannel in send_reconnect 2025-07-26 16:54:13 -07:00
Martin Michelsen bf028ed0f6 fix data2 handling in 30 command from GetExtendedPlayerInfo 2025-07-24 21:37:36 -07:00
Martin Michelsen 1ecc41dea9 format show-item-tables output more cleanly 2025-07-24 18:38:14 -07:00
Justin Schwartz 648e15a016 document the original unit stars random state 2025-07-22 23:18:53 -07:00
Martin Michelsen 1729edc1d2 add dynamic switching in EnemyDamageSync 2025-07-22 00:27:21 -07:00
Martin Michelsen bbcc03f832 improve CommonItemSet JSON parser/serializer 2025-07-20 22:30:04 -07:00
Martin Michelsen 6827229c83 refine 6x79 a bit 2025-07-20 22:30:01 -07:00
Martin Michelsen 60291993b6 add configurable min levels for non-BB; closes #666 2025-07-11 17:57:39 -07:00
Martin Michelsen 118512ebb2 fix websocket timeout 2025-07-10 09:38:31 -07:00
Martin Michelsen ae9eaccd29 fix disconnect for websocket clients 2025-07-08 20:09:20 -07:00
Martin Michelsen 3025420aea fix headers in show-item-tables 2025-07-08 20:09:04 -07:00
Martin Michelsen 3c4ad43e71 add belra arm bug fix 2025-07-06 23:25:03 -07:00
Martin Michelsen 9e02b6c666 add $sound command 2025-07-06 21:41:31 -07:00
Martin Michelsen fe435c13d3 fix local address detection 2025-07-06 20:48:44 -07:00
Martin Michelsen 3b5145880c fix $loadchar description in readme 2025-07-06 15:35:56 -07:00
Martin Michelsen d965ff5031 add stat boosts to ItemPMT formatting 2025-07-06 13:57:31 -07:00
Martin Michelsen 22a89deb8b fix save game data timer 2025-07-05 20:27:24 -07:00
Martin Michelsen c9ba61a4b0 fix NAME_ONLY for units with kill counts 2025-07-05 19:54:30 -07:00
Martin Michelsen 0cdf2784cc fix text alignment in MoreSaveSlots 2025-07-05 19:49:20 -07:00
Martin Michelsen 76a948a45d fix unused variable 2025-07-03 00:27:38 -07:00
Martin Michelsen fd39a89957 fix BB proxy bugs 2025-07-02 21:14:32 -07:00
Martin Michelsen 0a5065707c use new phosg::Image class 2025-07-01 09:56:42 -07:00
Martin Michelsen 072e647c7b update readme 2025-06-29 11:22:40 -07:00
Martin Michelsen 148db03a9a fix copy-paste error in MoreSaveSlots patch 2025-06-24 20:53:33 -07:00
Martin Michelsen cff5ad23fc fix scroll bar setup in MoreSaveSlots 2025-06-24 20:12:49 -07:00
Martin Michelsen 3e174b7397 add notes on TObjSinBoard 2025-06-24 20:12:33 -07:00
Martin Michelsen e9bf51f3f7 save all fields when applying npc skins 2025-06-24 20:12:24 -07:00
Martin Michelsen 28ab1bea9c add IPv6 support in proxy 2025-06-17 01:19:26 -07:00
Martin Michelsen 923cc4ebb0 add missing xbox includes 2025-06-16 19:22:38 -07:00
Martin Michelsen e24a0e3c40 decrypt Ep3 player config at load time 2025-06-16 00:30:53 -07:00
Martin Michelsen a857cc9d03 update some notes 2025-06-16 00:10:50 -07:00
Martin Michelsen 8746b544b6 describe the PCv2-exclusive quest opcodes 2025-06-14 20:40:53 -07:00
Martin Michelsen ccd5baedf1 add notes from BB trial edition 2025-06-14 12:00:36 -07:00
Martin Michelsen 9621e89cd7 add notes and support for final PCv2 version 2025-06-14 00:35:56 -07:00
Martin Michelsen 3844c9881c add AccurateKillCount patch 2025-06-12 18:49:38 -07:00
Martin Michelsen 6999694f89 rewrite 6xE4 logic 2025-06-12 01:27:54 -07:00
Martin Michelsen 54acd931da use .label/.address in xbox client functions 2025-06-09 10:00:38 -07:00
Martin Michelsen 9bc9e219b5 add patch for disabling Xbox save signature validation 2025-06-07 19:32:21 -07:00
Martin Michelsen e8b2765a71 add xbox disk file formats 2025-06-07 19:26:34 -07:00
Martin Michelsen d4bc880018 make $killcount work for units too 2025-06-07 09:53:56 -07:00
Martin Michelsen c1a2742617 update readme 2025-06-07 09:53:35 -07:00
Martin Michelsen ebaeb2f70a update docs for find_inventory_item quest opcode 2025-06-05 21:33:51 -07:00
Martin Michelsen 0366e36edb add Xbox-US1 quest handlers 2025-06-05 20:59:41 -07:00
Martin Michelsen a0f52f01bb use 6x2F for infinite HP 2025-06-04 00:18:57 -07:00
Martin Michelsen bee4c55446 make client functions parameterizable by version 2025-06-04 00:16:43 -07:00
Martin Michelsen 1a6b26e56b add text-only matching in AddressTranslator 2025-06-03 09:59:19 -07:00
Martin Michelsen 1047d089d5 fix 6x0B error message 2025-05-31 23:15:23 -07:00
Martin Michelsen 2d6096cfda fix $savechar on BB 2025-05-31 23:15:00 -07:00
Martin Michelsen 7cbd9402d0 fix CallNativeFunctionGC
Docker / Build (push) Has been cancelled
2025-05-31 15:15:03 -07:00
Martin Michelsen 0396337994 fix inventory/bank debug messages 2025-05-31 15:14:04 -07:00
Martin Michelsen 6fbc0829ae add patch to replace Pinz shop cards 2025-05-31 10:56:01 -07:00
Martin Michelsen 4f41cbc9ce fix description generated in $item command 2025-05-31 10:07:11 -07:00
Martin Michelsen d1e6d75d70 fix TethVer detection hack 2025-05-31 10:04:09 -07:00
Martin Michelsen 067f2439ca make redirect wait apply to SocketChannels as well 2025-05-31 09:34:09 -07:00
Martin Michelsen 2d2edbd7be fix ping exception handler 2025-05-31 09:29:01 -07:00
Vargur f5f457aa6f Fix HTTP endpoint logic: remove incorrect negation in rare-tables path check
The !req.path.starts_with( was causing every subsequent command to be processed as a rare-tables substring command.
2025-05-30 19:29:52 -07:00
Martin Michelsen aabbafb749 fix game flag translation across v2/v3 boundary 2025-05-28 22:01:54 -07:00
Martin Michelsen e72e37f713 implement extended $infhp features on proxy server; closes #501 2025-05-27 19:34:47 -07:00
Martin Michelsen f884893b18 reprioritize to-do list 2025-05-27 19:34:25 -07:00
Martin Michelsen c74c0e2250 fix conditions 2025-05-26 23:52:43 -07:00
Martin Michelsen 5f4d2ec891 complete implementation of $checkchar and make slot count configurable; closes #645 2025-05-26 21:55:19 -07:00
Martin Michelsen 33b0ab3ed3 improve BB proxy functionality 2025-05-26 18:56:23 -07:00
523 changed files with 16437 additions and 23447 deletions
+2
View File
@@ -14,6 +14,7 @@ CTestTestfile.cmake
install_manifest.txt
Makefile
Testing
build
# Files modified by the user and/or server that don't have defaults
system/config.json
@@ -35,6 +36,7 @@ system/patch-bb/.metadata-cache.json
# repository
files
make_release.py
notes-private
old-khyller
old-newserv
release
+65 -59
View File
@@ -26,7 +26,7 @@ See TODO.md for a list of known issues and future work I've curated, or go to th
* [Cross-version play](#cross-version-play)
* [Server-side saves](#server-side-saves)
* [Episode 3 features](#episode-3-features)
* [Memory patches, client functions, and DOL files](#memory-patches-client-functions-and-dol-files)
* [Memory patches, client functions, and DOL files](#memory-patches-and-client-functions)
* [Using newserv as a proxy](#using-newserv-as-a-proxy)
* [Chat commands](#chat-commands)
* [REST API](#rest-api)
@@ -54,16 +54,17 @@ At the time of its inception, Aeon was also called newserv, and you may find som
Independently of this project, there are many other PSO servers out there. Those that I know of that are (or were) public are listed here in approximate chronological order:
* (Early 2000s) **[Schtserv](https://schtserv.com/)**: The first public-access PSO server; written in Delphi by Schthack. Still active and popular as of early 2025. Schtserv is also the only other unofficial server to support all versions of PSO, including Episode 3. (Their implementation of Episode 3 is based on newserv's, which is itself based on Sega's.)
* (Early 2000s) **[Schtserv](https://schtserv.com/)**: The first public-access PSO server, written in Delphi by Schthack. Schtserv is the only other unofficial server to support Episode 3, their implementation of which is based on newserv's (which is based on Sega's).
* (2005) **Khyller**: An early attempt of mine to support PSO PC, GC, and BB. See above for more details.
* (2006) **Aeon**: My second attempt. Better than Khyller, but still unreliable.
* (2008) **Tethealla**: A fairly extensive implementation of PSOBB, written in C by Sodaboy. The public version of Tethealla has been [officially disowned](https://www.pioneer2.net/community/threads/tethealla-server-forums-removal.26365/) (as it is now more than 15 years old), but closed-source development continues. [Ephinea](https://ephinea.pioneer2.net/), currently the most popular PSOBB server, is the continuation of this project. Several other modern PSOBB servers are forks of the initial public version of Tethealla as well.
* (2008) **[Sylverant](https://sylverant.net/)** [(source)](https://sourceforge.net/projects/sylverant/): The second public-access PSO server; written in C by BlueCrab. Still active and popular as of early 2025.
* (2008) **Tethealla**: A fairly extensive implementation of PSOBB, written in C by Sodaboy. The public version of Tethealla has been [officially disowned](https://www.pioneer2.net/community/threads/tethealla-server-forums-removal.26365/) as it is now more than 15 years old, but closed-source development continues. [Ephinea](https://ephinea.pioneer2.net/) is the continuation of this project. Several other modern PSOBB servers are forks of the initial public version of Tethealla as well.
* (2008) **[Sylverant](https://sylverant.net/)** [(source)](https://sourceforge.net/projects/sylverant/): The second public-access PSO server, written in C by BlueCrab.
* (2015) **[Archon](https://github.com/dcrodman/archon)**: A PSOBB server written in Go by Drew Rodman.
* (2015) **[Idola](https://github.com/HybridEidolon/idolapsoserv)**: A PSOBB server written in Rust by HybridEidolon. Functionality status unknown; the project has been archived.
* (2017) **[Aselia](https://github.com/Solybum/Aselia)**: A PSOBB server written written in C# by Soly. It seems this was planned to be open-source at some point, but that has not (yet) happened.
* (2017) **[Aselia](https://github.com/Solybum/Aselia)**: A PSOBB server written in C# by Soly. It seems this was planned to be open-source at some point, but that has not (yet) happened.
* (2018) **newserv**: This project right here.
* (2019) **[Mechonis](https://gitlab.com/sora3087/mechonis)**: A PSOBB server with a microservice architecture written in TypeScript by TrueVision.
* (2020) **[Booma.Server](https://github.com/HelloKitty/Booma.Server)**: A PSOBB server written in C# by Glader, with Soly's help.
* (2021) **[Phantasmal World](https://github.com/DaanVandenBosch/phantasmal-world)**: A set of PSO tools, including a web-based model viewer and quest builder, and a PSO server, written by Daan Vanden Bosch.
* (2021) **[Elseware](http://git.sharnoth.com/jake/elseware)**: A PSOBB server written in Rust by Jake.
@@ -136,12 +137,10 @@ Currently newserv works on macOS, Windows, and Ubuntu Linux. It will likely work
1. Download the latest release.zip file from the [releases page](https://github.com/fuzziqersoftware/newserv/releases).
2. Extract the contents of the archive to some location on your computer.
3. (Optional) If you want to change any config options, go into the system/ folder, open config.json in a text editor, and edit it to your liking. There are comments in the file that describe what all the options do.
3. Go into the system/ folder, open config.json in a text editor, and edit it to your liking. There are comments in the file that describe what all the options do. Most of the options can be left alone if you want default behavior, but on Windows, you must change LocalAddress and ExternalAddress.
4. (Optional) If you plan to play Blue Burst on newserv, set up the patch directory. See [client patch directories](#client-patch-directories) for details.
5. Run the newserv executable.
If you're on an older version of Windows (before Windows 10), the Cygwin libraries included with the release may be incompatible. See [this issue](https://github.com/fuzziqersoftware/newserv/issues/621) for a possible workaround.
### Linux
There are currently no precompiled releases for Linux. To run newserv on Linux, you'll have to build it from source - see the section below.
@@ -448,7 +447,7 @@ There is no public editor for Episode 3 maps and quests, but the format is descr
Like quests, Episode 3 card definitions, maps, and quests are cached in memory. If you've changed any of these files, you can run `reload ep3-cards` or `reload ep3-maps` in the interactive shell to make the changes take effect without restarting the server.
## Memory patches, client functions, and DOL files
## Memory patches and client functions
You can put assembly files in the system/client-functions directory with filenames like PatchName.VERS.patch.s and they will appear in the Patches menu for clients that support client functions. Client functions are written in SH-4, PowerPC, or x86 assembly and are compiled when newserv is started. The assembly system's features are documented in the comments in system/client-functions/System/WriteMemoryGC.ppc.s.
@@ -456,50 +455,53 @@ The VERS token in client function filenames refers to the specific version of th
The specific versions are:
| Game | VERS | Architecture |
|------------------------------|------|---------------|
| PSO DC Network Trial Edition | 1OJ1 | Not supported |
| PSO DC 11/2000 prototype | 1OJ2 | Not supported |
| PSO DC 12/2000 prototype | 1OJ3 | Not supported |
| PSO DC 01/2001 prototype | 1OJ4 | Not supported |
| PSO DC v1 JP | 1OJF | Not supported |
| PSO DC v1 US | 1OEF | Not supported |
| PSO DC v1 EU | 1OPF | Not supported |
| PSO DC 08/2001 prototype | 2OJ5 | SH-4 |
| PSO DC v2 JP | 2OJF | SH-4 |
| PSO DC v2 US | 2OEF | SH-4 |
| PSO DC v2 EU | 2OPF | SH-4 |
| PSO PC (v2) | 2OJW | Not supported |
| PSO GC Trial Edition | 3OJT | PowerPC |
| PSO GC v1.2 JP | 3OJ2 | PowerPC |
| PSO GC v1.3 JP | 3OJ3 | PowerPC |
| PSO GC v1.4 (Plus) JP | 3OJ4 | PowerPC |
| PSO GC v1.5 (Plus) JP | 3OJ5 | PowerPC (1) |
| PSO GC v1.0 US | 3OE0 | PowerPC |
| PSO GC v1.1 US | 3OE1 | PowerPC |
| PSO GC v1.2 (Plus) US | 3OE2 | PowerPC (1) |
| PSO GC v1.0 EU | 3OP0 | PowerPC |
| PSO GC Ep3 Trial Edition | 3SJT | PowerPC |
| PSO GC Ep3 JP | 3SJ0 | PowerPC |
| PSO GC Ep3 US | 3SE0 | PowerPC (1) |
| PSO GC Ep3 EU | 3SP0 | PowerPC (1) |
| PSO Xbox Beta | 4OJB | x86 |
| PSO Xbox JP Disc | 4OJD | x86 |
| PSO Xbox JP TU | 4OJU | x86 |
| PSO Xbox US Disc | 4OED | x86 |
| PSO Xbox US TU | 4OEU | x86 |
| PSO Xbox EU Disc | 4OPD | x86 |
| PSO Xbox EU TU | 4OPU | x86 |
| PSO BB JP 1.25.11 | 59NJ | x86 |
| PSO BB JP 1.25.13 | 59NL | x86 |
| PSO BB Tethealla | 59NL | x86 |
| Game | VERS | CPU architecture |
|------------------------------|------|--------------------------------|
| PSO DC Network Trial Edition | 1OJ1 | Client functions not supported |
| PSO DC 11/2000 prototype | 1OJ2 | Client functions not supported |
| PSO DC 12/2000 prototype | 1OJ3 | Client functions not supported |
| PSO DC 01/2001 prototype | 1OJ4 | Client functions not supported |
| PSO DC v1 JP | 1OJF | Client functions not supported |
| PSO DC v1 US | 1OEF | Client functions not supported |
| PSO DC v1 EU | 1OPF | Client functions not supported |
| PSO DC 08/2001 prototype | 2OJ5 | SH-4 |
| PSO DC v2 JP | 2OJF | SH-4 |
| PSO DC v2 US | 2OEF | SH-4 |
| PSO DC v2 EU | 2OPF | SH-4 |
| PSO PC (v2) 04/2002 | 2OJW | Client functions not supported |
| PSO PC (v2) 02/2003 | 2OJZ | Client functions not supported |
| PSO GC Trial Edition | 3OJT | PowerPC |
| PSO GC v1.2 JP | 3OJ2 | PowerPC |
| PSO GC v1.3 JP | 3OJ3 | PowerPC |
| PSO GC v1.4 (Plus) JP | 3OJ4 | PowerPC |
| PSO GC v1.5 (Plus) JP | 3OJ5 | PowerPC (1) |
| PSO GC v1.0 US | 3OE0 | PowerPC |
| PSO GC v1.1 US | 3OE1 | PowerPC |
| PSO GC v1.2 (Plus) US | 3OE2 | PowerPC (1) |
| PSO GC v1.0 EU | 3OP0 | PowerPC |
| PSO GC Ep3 Trial Edition | 3SJT | PowerPC |
| PSO GC Ep3 JP | 3SJ0 | PowerPC |
| PSO GC Ep3 US | 3SE0 | PowerPC (1) |
| PSO GC Ep3 EU | 3SP0 | PowerPC (1) |
| PSO Xbox Beta | 4OJB | x86 |
| PSO Xbox JP Disc | 4OJD | x86 |
| PSO Xbox JP TU | 4OJU | x86 |
| PSO Xbox US Disc | 4OED | x86 |
| PSO Xbox US TU | 4OEU | x86 |
| PSO Xbox EU Disc | 4OPD | x86 |
| PSO Xbox EU TU | 4OPU | x86 |
| PSO BB JP 1.25.11 | 59NJ | x86 |
| PSO BB JP 1.25.13 | 59NL | x86 |
| PSO BB Tethealla | 59NL | x86 |
*Notes:*
1. *Client functions are only supported on these versions if EnableSendFunctionCallQuestNumbers is set in config.json. See the comments there for more information.*
newserv comes with a set of patches for many of the above versions, based on AR codes originally made by Ralf at GC-Forever and Aleron Ives. Many of them were originally posted in [this thread](https://www.gc-forever.com/forums/viewtopic.php?f=38&t=2050).
newserv comes with a set of patches for many of the above versions. These are organized in subdirectories within system/client-functions/.
You can also put DOL files in the system/dol directory, and they will appear in the Programs menu for GC clients. Selecting a DOL file there will load the file into the GameCube's memory and run it, just like the old homebrew loaders (PSUL and PSOload) did. For this to work, ReadMemoryWordGC.ppc.s, WriteMemoryGC.ppc.s, and RunDOL.ppc.s must be present in the system/client-functions/System directory. This has been tested on Dolphin but not on a real GameCube, so results may vary.
### DOL loader
You can put DOL files in the system/dol directory, and they will appear in the Programs menu for GC clients. Selecting a DOL file there will load the file into the GameCube's memory and run it, just like the old homebrew loaders (PSUL and PSOload) did. For this to work, ReadMemoryWordGC.ppc.s, WriteMemoryGC.ppc.s, and RunDOL.ppc.s must be present in the system/client-functions/System directory. This has been tested on Dolphin but not on a real GameCube, so results may vary.
Like other kinds of data, functions and DOL files are cached in memory. If you've changed any of these files, you can run `reload functions` or `reload dol-files` in the interactive shell to make the changes take effect without restarting the server.
@@ -562,22 +564,25 @@ Some commands only work for clients not in proxy sessions. The chat commands are
* `$where`: Show your current floor number and coordinates. Mainly useful for debugging.
* `$qfread <field-name>` (non-proxy only): Show the value of a quest counter in your player data. The field names are defined in config.json.
* Debugging commands
* `$debug`: Enable or disable debug. You need the DEBUG flag in your user account to use this command. Enabling debug does several things:
* Basic debugging commands (special permissions not required)
* `$whatobj` and `$whatene` (non-proxy only): Tells you what the closest object or enemy spawn point is to your position, along with its coordinates and object or enemy ID. The full definition is also printed to the server's log.
* `$qcheck <flag-num>` (non-proxy only): Show the value of a quest flag. If you're in a game, show the value of the flag in that game; if you're in the lobby, show the saved value of that quest flag for your character (BB only).
* `$qgread <flag-num>` (non-proxy only): Show the value of a quest counter ("global flag").
* `$sound <sound-id>`: Play the given sound (GC only).
* Restricted debugging commands (`$debug` permission required)
* `$debug`: Enable debug mode. You need the DEBUG flag in your user account to use this command. Enabling debug does several things:
* You'll be able to use the rest of the commands in this section.
* You'll see in-game messages from the server when you take some actions, like killing enemies, opening boxes, or flipping switches.
* You'll see the rare seed value and floor variations when you join a game.
* You'll be placed into the last available slot in lobbies and games instead of the first, unless you're joining a BB solo-mode game.
* You'll be able to join games with any PSO version, not only those for which cross-version play is normally enabled. See the "Cross-version play" section above for details on this.
* Most of the commands in this section are enabled. (A few of them are always enabled and don't require `$debug`.)
* `$whatobj` and `$whatene` (non-proxy only): Tells you what the closest object or enemy spawn point is to your position, along with its coordinates and object or enemy ID. The full definition is also printed to the server's log. These commands can be used without `$debug` enabled.
* `$readmem <address>`: Read 4 bytes from the given address and show you the values.
* `$writemem <address> <data>`: Write data to the given address. Data is not required to be any specific size.
* `$nativecall <address> [arg1 ...]` (GC only): Call a native function on your client. Only arguments passed in registers are supported; calling functions that take many arguments is not supported.
* `$quest <number>` (non-proxy only): Load a quest by quest number. Can be used to load battle or challenge quests with only one player present. `$debug` is not required for this command if the specified quest has the AllowStartFromChatCommand field set in its metadata file.
* `$qcall <function-id>`: Call a quest function on your client.
* `$qcheck <flag-num>` (non-proxy only): Show the value of a quest flag. This command can be used without `$debug` enabled. If you're in a game, show the value of the flag in that game; if you're in the lobby, show the saved value of that quest flag for your character (BB only).
* `$qset <flag-num>` or `$qclear <flag-num>`: Set or clear a quest flag for everyone in the game. If you're in the lobby and on BB, set or clear the saved value of a quest flag in your character file.
* `$qgread <flag-num>` (non-proxy only): Show the value of a quest counter ("global flag"). This command can be used without `$debug` enabled.
* `$qgwrite <flag-num> <value>` (non-proxy only): Set the value of a quest counter ("global flag") for yourself.
* `$qsync <reg-num> <value>`: Set a quest register's value for yourself only. `<reg-num>` should be either rXX (e.g. r60) or fXX (e.g. f60); if the latter, `<value>` is parsed as a floating-point value instead of as an integer.
* `$qsyncall <reg-num> <value>`: Set a quest register's value for everyone in the game. `<reg-num>` should be either rXX (e.g. r60) or fXX (e.g. f60); if the latter, `<value>` is parsed as a floating-point value instead of as an integer.
@@ -587,7 +592,7 @@ Some commands only work for clients not in proxy sessions. The chat commands are
* `$sc <data>`: Send a command to yourself.
* `$ss <data>`: Send a command to the remote server (if in a proxy session) or to the game server.
* `$sb <data>`: Send a command to yourself, and to the remote server or game server.
* `$auction` (Episode 3 only): Bring up the CARD Auction menu, regardless of how many players are in the game or if you have a VIP card.
* `$auction` (Episode 3 only): Bring up the CARD Auction menu, even if there are fewer than 4 players are in the game or you don't have a VIP card.
* Personal state commands
* `$arrow <color-id>`: Change your lobby arrow color. The color may be specified by number (0-12) or by name (red, blue, green, yellow, purple, cyan, orange, pink, white, white2, white3, or black).
@@ -600,9 +605,9 @@ Some commands only work for clients not in proxy sessions. The chat commands are
* Character data commands (non-proxy only)
* `$savechar <slot>`: Save your current character data on the server in the specified slot. See the [server-side saves section](#server-side-saves) for more details.
* `$loadchar <slot>`: Save your current character data on the server in the specified slot. See the [server-side saves section](#server-side-saves) for more details.
* `$loadchar <slot>`: Load character data from the specified slot on the server, and replace your current character with it. See the [server-side saves section](#server-side-saves) for more details.
* `$bbchar <username> <password> <slot>`: Save your current character data on the server in a different account's BB character slots. See the [server-side saves section](#server-side-saves) for more details.
* `$checkchar <slot>`: Tells you basic information about a server-side character previously saved using `$savechar`.
* `$checkchar [slot]`: Tells you basic information about a server-side character previously saved using `$savechar`. If `slot` is not given, tells you which slots are used and which are free.
* `$deletechar <slot>`: Deletes a server-side character previously saved using `$savechar`.
* `$edit <stat> <value>`: Modify your character data. See the [using $edit](#using-edit) section for details.
@@ -628,8 +633,8 @@ Some commands only work for clients not in proxy sessions. The chat commands are
* Cheat mode commands
* `$cheat` (non-proxy only): Enable or disable cheat mode for the current game. All other cheat mode commands do nothing if cheat mode is disabled. By default, cheat mode is off in new games but can be enabled; there is an option in config.json that allows you to disable cheat mode entirely, or set it to on by default in new games. Cheat mode is always enabled on the proxy, unless cheat mode is disabled on the entire server.
* `$infhp`: Enable or disable infinite HP mode. Applies to only you; does not affect other players. When enabled, one-hit KO attacks will still kill you, but on most versions of the game (not DCv1, GC US 1.2, or GC JP 1.5), the server will automatically revive you if you die. On all versions except GC US 1.2 and GC JP 1.5, infinite HP also automatically cures status ailments.
* `$inftp`: Enable or disable infinite TP mode. Applies to only you; does not affect other players.
* `$infhp`: Enable or disable infinite HP mode. Applies to only you; does not affect other players. When enabled, one-hit KO attacks will still kill you, but on most versions of the game, the server will automatically revive you if you die. Infinite HP also automatically cures status ailments.
* `$inftp`: Enable or disable infinite TP mode. Applies to only you; does not affect other players. Does not work on DCv1 or earlier versions.
* `$warpme <floor-id>` (or `$warp <floor-id>`): Warp yourself to the given floor.
* `$warpall <floor-id>`: Warp everyone in the game to the given floor. You must be the leader to use this command, unless you're on the proxy.
* `$next`: Warp yourself to the next floor.
@@ -753,6 +758,7 @@ The data formats that newserv can convert to/from are:
| PSO DC save file (.vms) | `encrypt-vms-save` | `decrypt-vms-save` |
| PSO PC save file | `encrypt-pc-save` | `decrypt-pc-save` |
| PSO GC save file (.gci) | `encrypt-gci-save` | `decrypt-gci-save` |
| PSO Xbox save file | None | `decrypt-xbox-save` |
| PSO GC snapshot file | None | `decode-gci-snapshot` |
| Quest script (.bin) | `assemble-quest-script` | `disassemble-quest-script` |
| Quest map (.dat) | None | `disassemble-quest-map` |
+6 -5
View File
@@ -1,13 +1,14 @@
## General
- Make UI strings localizable (e.g. entries in menus, welcome message, etc.)
- Clean up ItemParameterTable implementation (see comment at the top of the class definition)
- Handle MeetUserExtensions properly in 41 and C4 commands on the proxy (rewrite the embedded 19 command and put some metadata in the persistent config, perhaps)
- Make a server patch version of story flag fixer quest
- Make proxy server handle all login commands, including sending 9C when needed
- Fix enemy flag mapping in v2/v3 crossplay and test
- Handle items in crossplay - use the replacement table
- Make proxy server handle all login commands on non-BB, including sending 9C when needed
- Add $switchit command (activates switch flag(s) for nearest object, e.g. laser fence, door, fog collision)
- Add a way to persist flags across connections, at least on v3, because of Meet User + B2 enable quest interactions - maybe update the quest to patch one of the login commands so the server can tell it's enabled
- Handle items in crossplay - use the replacement table
- Handle MeetUserExtensions properly in 41 and C4 commands on the proxy (rewrite the embedded 19 command and put some metadata in the persistent config, perhaps)
- Clean up ItemParameterTable implementation (see comment at the top of the class definition)
- Make UI strings localizable (e.g. entries in menus, welcome message, etc.)
## PSO DC
+11 -1
View File
@@ -17,7 +17,8 @@ Version codes (from README.md):
2OJF: PSO DC v2 JP
2OEF: PSO DC v2 US
2OPF: PSO DC v2 EU
2OJW: PSO PC (v2)
2OJW: PSO PC (v2) 04/2002
2OJZ: PSO PC (v2) 02/2003
3OJT: PSO GC Trial Edition
3OJ2: PSO GC v1.2 JP
3OJ3: PSO GC v1.3 JP
@@ -722,3 +723,12 @@ Show extended item info when targeting a dropped item
All weapons can do 3-hit combos
3OE1 => 041D3248 38000001
Disable save file signature validation (for moving Xbox saves across consoles)
4OJB => 002F01CB 9090
4OJD => 002F0CDB 9090
4OJU => 002F22DB 9090
4OED => 002F212B 9090
4OEU => 002F22DB 9090
4OPD => 002F215B 9090
4OPU => 002F234B 9090
+929 -926
View File
File diff suppressed because it is too large Load Diff
+52 -6
View File
@@ -635,7 +635,13 @@ public:
throw runtime_error("scan field too long; too many matches");
}
void find_all_matches(uint32_t src_addr, uint32_t src_size) const {
enum class MatchType {
ANY = 0,
TEXT,
DATA,
};
void find_all_matches(uint32_t src_addr, uint32_t src_size, MatchType type) const {
if (!this->src_mem) {
throw runtime_error("no source file selected");
}
@@ -660,19 +666,48 @@ public:
ExpandMethod::PPC_DATA_BACKWARD,
ExpandMethod::PPC_DATA_BOTH,
};
static const vector<ExpandMethod> ppc_text_methods = {
ExpandMethod::PPC_TEXT_FORWARD,
ExpandMethod::PPC_TEXT_FORWARD_WITH_BARRIER,
ExpandMethod::PPC_TEXT_BACKWARD,
ExpandMethod::PPC_TEXT_BACKWARD_WITH_BARRIER,
ExpandMethod::PPC_TEXT_BOTH,
ExpandMethod::PPC_TEXT_BOTH_WITH_BARRIER,
ExpandMethod::PPC_TEXT_BOTH_IGNORE_ORIGIN,
};
static const vector<ExpandMethod> ppc_data_methods = {
ExpandMethod::PPC_DATA_FORWARD,
ExpandMethod::PPC_DATA_BACKWARD,
ExpandMethod::PPC_DATA_BOTH,
};
static const vector<ExpandMethod> raw_methods = {
ExpandMethod::RAW_FORWARD,
ExpandMethod::RAW_BACKWARD,
ExpandMethod::RAW_BOTH,
};
const auto& methods = this->ppc_mems.count(it.second) ? ppc_methods : raw_methods;
for (size_t z = 0; z < methods.size(); z++) {
futures.emplace_back(async(&AddressTranslator::find_match, this, it.second, src_addr, src_size, methods[z]));
const vector<ExpandMethod>* methods;
if (this->ppc_mems.count(it.second)) {
if (type == MatchType::ANY) {
methods = &ppc_methods;
} else if (type == MatchType::TEXT) {
methods = &ppc_text_methods;
} else if (type == MatchType::DATA) {
methods = &ppc_data_methods;
} else {
throw logic_error("invalid match type");
}
} else {
methods = &raw_methods;
}
for (size_t z = 0; z < methods->size(); z++) {
futures.emplace_back(async(&AddressTranslator::find_match, this, it.second, src_addr, src_size, methods->at(z)));
}
unordered_set<uint32_t> match_addrs;
for (size_t z = 0; z < futures.size(); z++) {
const char* method_name = this->name_for_expand_method(methods[z]);
const char* method_name = this->name_for_expand_method(methods->at(z));
try {
uint32_t ret = futures[z].get();
log.info_f("({}) ({}) {:08X}", it.first, method_name, ret);
@@ -831,7 +866,18 @@ public:
} else if (tokens[0] == "match") {
this->find_all_matches(
stoul(tokens.at(1), nullptr, 16),
tokens.size() >= 3 ? stoul(tokens[2], nullptr, 16) : 0);
tokens.size() >= 3 ? stoul(tokens[2], nullptr, 16) : 0,
MatchType::ANY);
} else if (tokens[0] == "match-text") {
this->find_all_matches(
stoul(tokens.at(1), nullptr, 16),
tokens.size() >= 3 ? stoul(tokens[2], nullptr, 16) : 0,
MatchType::TEXT);
} else if (tokens[0] == "match-data") {
this->find_all_matches(
stoul(tokens.at(1), nullptr, 16),
tokens.size() >= 3 ? stoul(tokens[2], nullptr, 16) : 0,
MatchType::DATA);
} else if (tokens[0] == "match-be-le") {
this->find_all_be_to_le_data_matches(
stoul(tokens.at(1), nullptr, 16),
+6 -4
View File
@@ -87,7 +87,7 @@ struct HTTPServerLimits {
size_t max_http_data_size = 0x200000; // 2MB
size_t max_http_keepalive_idle_usecs = 300 * 1000 * 1000; // 5 minutes (0 = no limit)
size_t max_websocket_message_size = 0x200000; // 2MB
size_t max_websocket_idle_usecs = 300 * 1000 * 1000; // 5 minutes (0 = no limit)
size_t max_websocket_idle_usecs = 0; // No limit by default
};
extern const HTTPServerLimits DEFAULT_HTTP_LIMITS;
@@ -205,9 +205,11 @@ protected:
if (resp) {
co_await c->send_http_response(*resp);
}
auto* conn_header = req.get_header("connection");
if (!conn_header || (*conn_header != "keep-alive")) {
c->r.close();
if (!c->is_websocket) {
auto* conn_header = req.get_header("connection");
if (!conn_header || (*conn_header != "keep-alive")) {
c->r.close();
}
}
}
+9 -1
View File
@@ -224,6 +224,14 @@ inline asio::ip::tcp::endpoint make_endpoint_ipv4(uint32_t addr, uint16_t port)
return asio::ip::tcp::endpoint(asio::ip::address_v4(addr), port);
}
inline asio::ip::tcp::endpoint make_endpoint_ipv6(const void* addr, uint16_t port) {
std::array<uint8_t, 0x10> bytes;
for (size_t z = 0; z < 0x10; z++) {
bytes[z] = reinterpret_cast<const uint8_t*>(addr)[z];
}
return asio::ip::tcp::endpoint(asio::ip::address_v6(bytes), port);
}
inline std::string str_for_endpoint(const asio::ip::tcp::endpoint& ep) {
return ep.address().to_string() + std::format(":{}", ep.port());
}
@@ -232,7 +240,7 @@ inline uint32_t ipv4_addr_for_asio_addr(const asio::ip::address& addr) {
if (!addr.is_v4()) {
throw std::runtime_error("Address is not IPv4");
}
return ntohl(addr.to_v4().to_uint());
return addr.to_v4().to_uint();
}
asio::awaitable<asio::ip::tcp::socket> async_connect_tcp(uint32_t ipv4_addr, uint16_t port);
+14 -6
View File
@@ -9,10 +9,17 @@
using namespace std;
void BattleParamsIndex::Table::print(FILE* stream) const {
auto print_entry = +[](FILE* stream, const PlayerStats& e) {
void BattleParamsIndex::Table::print(FILE* stream, Episode episode) const {
auto print_entry = [stream, episode](const PlayerStats& e, size_t z) {
string names_str;
for (auto type : enemy_types_for_battle_param_index(episode, z)) {
if (!names_str.empty()) {
names_str += ", ";
}
names_str += phosg::name_for_enum(type);
}
phosg::fwrite_fmt(stream,
"{:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5}",
"{:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {}",
e.char_stats.atp,
e.char_stats.mst,
e.char_stats.evp,
@@ -22,15 +29,16 @@ void BattleParamsIndex::Table::print(FILE* stream) const {
e.char_stats.lck,
e.esp,
e.experience,
e.meseta);
e.meseta,
names_str);
};
for (size_t diff = 0; diff < 4; diff++) {
phosg::fwrite_fmt(stream, "{} ZZ ATP PSV EVP HP DFP ATA LCK ESP EXP DIFF\n",
phosg::fwrite_fmt(stream, "{} ZZ ATP PSV EVP HP DFP ATA LCK ESP EXP DIFF NAMES\n",
abbreviation_for_difficulty(diff));
for (size_t z = 0; z < 0x60; z++) {
phosg::fwrite_fmt(stream, " {:02X} ", z);
print_entry(stream, this->stats[diff][z]);
print_entry(this->stats[diff][z], z);
fputc('\n', stream);
}
}
+1 -1
View File
@@ -76,7 +76,7 @@ public:
/* AE00 */ parray<parray<MovementData, 0x60>, 4> movement_data;
/* F600 */
void print(FILE* stream) const;
void print(FILE* stream, Episode episode) const;
} __packed_ws__(Table, 0xF600);
BattleParamsIndex(
+147 -90
View File
@@ -24,6 +24,41 @@
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// Tools
string str_for_flag_ranges(const vector<bool>& flags) {
string ret;
auto add_result = [&](size_t start, size_t end) {
if (!ret.empty()) {
ret.push_back(',');
}
if (start == end) {
ret += std::format("{}", start);
} else if (start == end - 1) {
ret += std::format("{},{}", start, end);
} else {
ret += std::format("{}-{}", start, end);
}
};
size_t range_start = 0;
bool in_range = false;
for (size_t z = 0; z < flags.size(); z++) {
if (flags[z] && !in_range) {
in_range = true;
range_start = z;
} else if (!flags[z] && in_range) {
in_range = false;
add_result(range_start, z - 1);
}
}
if (in_range) {
add_result(range_start, flags.size() - 1);
}
return ret;
}
////////////////////////////////////////////////////////////////////////////////
// Checks
@@ -421,7 +456,7 @@ static asio::awaitable<void> server_command_bbchar_savechar(const Args& a, bool
shared_ptr<Account> dest_account;
shared_ptr<BBLicense> dest_bb_license;
ssize_t dest_character_index = 0;
size_t dest_character_index = 0;
if (is_bb_conversion) {
vector<string> tokens = phosg::split(a.text, ' ');
if (tokens.size() != 3) {
@@ -429,9 +464,9 @@ static asio::awaitable<void> server_command_bbchar_savechar(const Args& a, bool
}
// username/password are tokens[0] and [1]
dest_character_index = stoll(tokens[2]) - 1;
if ((dest_character_index > 3) || (dest_character_index < 0)) {
throw precondition_failed("$C6Player index must\nbe in range 1-4");
dest_character_index = stoull(tokens[2]) - 1;
if (dest_character_index >= 127) {
throw precondition_failed("$C6Player index must\nbe in range 1-127");
}
try {
@@ -443,16 +478,22 @@ static asio::awaitable<void> server_command_bbchar_savechar(const Args& a, bool
}
} else {
dest_character_index = stoll(a.text) - 1;
if ((dest_character_index > 15) || (dest_character_index < 0)) {
throw precondition_failed("$C6Player index must\nbe in range 1-16");
dest_character_index = stoull(a.text) - 1;
if (dest_character_index >= s->num_backup_character_slots) {
throw precondition_failed("$C6Player index must\nbe in range 1-{}", s->num_backup_character_slots);
}
dest_account = a.c->login->account;
}
// If the client isn't BB, request the player info. (If they are BB, the
// server already has it)
auto ch = co_await send_get_player_info(a.c, true);
GetPlayerInfoResult ch;
if (a.c->version() == Version::BB_V4) {
ch.character = a.c->character();
ch.is_full_info = true;
} else {
ch = co_await send_get_player_info(a.c, true);
}
string filename = dest_bb_license
? Client::character_filename(dest_bb_license->username, dest_character_index)
@@ -574,30 +615,49 @@ ChatCommandDefinition cc_checkchar(
throw precondition_failed("$C7This command cannot\nbe used on a shared\naccount");
}
size_t index = stoull(a.text, nullptr, 0) - 1;
if (index > 15) {
throw precondition_failed("$C6Player index must\nbe in range 1-16");
}
auto s = a.c->require_server_state();
try {
if (is_ep3(a.c->version())) {
string filename = a.c->backup_character_filename(a.c->login->account->account_id, index, true);
auto ch = phosg::load_object_file<PSOGCEp3CharacterFile::Character>(filename);
send_text_message_fmt(a.c, "Slot {}: $C6{}$C7\n{} {}\nCLv: on {}.{}, off {}.{}",
index + 1, ch.disp.visual.name.decode(),
name_for_section_id(ch.disp.visual.section_id), name_for_char_class(ch.disp.visual.char_class),
(ch.ep3_config.online_clv_exp / 100) + 1, ch.ep3_config.online_clv_exp % 100,
(ch.ep3_config.offline_clv_exp / 100) + 1, ch.ep3_config.offline_clv_exp % 100);
} else {
string filename = a.c->backup_character_filename(a.c->login->account->account_id, index, false);
auto ch = PSOCHARFile::load_shared(filename, false).character_file;
send_text_message_fmt(a.c, "Slot {}: $C6{}$C7\n{} {}\nLevel {}",
index + 1, ch->disp.name.decode(),
name_for_section_id(ch->disp.visual.section_id), name_for_char_class(ch->disp.visual.char_class),
ch->disp.stats.level + 1);
if (a.text.empty()) {
bool is_ep3 = ::is_ep3(a.c->version());
vector<bool> flags;
flags.emplace_back(false);
for (size_t z = 0; z < s->num_backup_character_slots; z++) {
string filename = a.c->backup_character_filename(a.c->login->account->account_id, z, is_ep3);
flags.emplace_back(std::filesystem::is_regular_file(filename));
}
string used_str = str_for_flag_ranges(flags);
flags.flip();
flags[0] = false;
string free_str = str_for_flag_ranges(flags);
send_text_message_fmt(a.c, "Used: {}\nFree: {}", used_str, free_str);
} else {
size_t index = stoull(a.text, nullptr, 0) - 1;
if (index >= s->num_backup_character_slots) {
throw precondition_failed("$C6Player index must\nbe in range 1-{}", s->num_backup_character_slots);
}
try {
if (is_ep3(a.c->version())) {
string filename = a.c->backup_character_filename(a.c->login->account->account_id, index, true);
auto ch = phosg::load_object_file<PSOGCEp3CharacterFile::Character>(filename);
send_text_message_fmt(a.c, "Slot {}: $C6{}$C7\n{} {}\nCLv: on {}.{}, off {}.{}",
index + 1, ch.disp.visual.name.decode(),
name_for_section_id(ch.disp.visual.section_id), name_for_char_class(ch.disp.visual.char_class),
(ch.ep3_config.online_clv_exp / 100) + 1, ch.ep3_config.online_clv_exp % 100,
(ch.ep3_config.offline_clv_exp / 100) + 1, ch.ep3_config.offline_clv_exp % 100);
} else {
string filename = a.c->backup_character_filename(a.c->login->account->account_id, index, false);
auto ch = PSOCHARFile::load_shared(filename, false).character_file;
send_text_message_fmt(a.c, "Slot {}: $C6{}$C7\n{} {}\nLevel {}",
index + 1, ch->disp.name.decode(),
name_for_section_id(ch->disp.visual.section_id), name_for_char_class(ch->disp.visual.char_class),
ch->disp.stats.level + 1);
}
} catch (const phosg::cannot_open_file&) {
send_text_message_fmt(a.c, "No character in\nslot {}", index + 1);
}
} catch (const phosg::cannot_open_file&) {
send_text_message_fmt(a.c, "No character in\nslot {}", index + 1);
}
co_return;
@@ -941,46 +1001,13 @@ ChatCommandDefinition cc_edit(
if (tokens.at(1) == "none") {
p->disp.visual.extra_model = 0;
p->disp.visual.validation_flags &= 0xFD;
// Restore saved fields, if any
if (p->disp.visual.unused[0] == 0x8D) {
p->disp.visual.char_class = p->disp.visual.unused[1];
p->disp.visual.head = p->disp.visual.unused[2];
p->disp.visual.hair = p->disp.visual.unused[3];
p->disp.visual.unused.clear(0);
}
p->disp.visual.restore_npc_saved_fields();
} else {
uint8_t npc = npc_for_name(tokens.at(1), a.c->version());
if (npc == 0xFF) {
throw precondition_failed("$C6No such NPC");
}
// Some NPCs can crash the client if the character's class is
// incorrect. To handle this, we save the affected fields in the unused
// bytes after extra_model.
int8_t replacement_class = -1;
switch (npc) {
case 1: // Rico (replace with HUnewearl)
case 6: // Elly (replace with HUnewearl)
replacement_class = 0x01;
break;
case 0: // Ninja (replace with HUmar)
case 2: // Sonic (replace with HUmar)
case 5: // Flowen (replace with HUmar)
replacement_class = 0x00;
break;
}
if (replacement_class >= 0) {
if (p->disp.visual.unused[0] != 0x8D) {
p->disp.visual.unused[0] = 0x8D;
p->disp.visual.unused[1] = p->disp.visual.char_class;
p->disp.visual.unused[2] = p->disp.visual.head;
p->disp.visual.unused[3] = p->disp.visual.hair;
}
p->disp.visual.char_class = replacement_class;
p->disp.visual.head = 0x00;
p->disp.visual.hair = 0x00;
}
p->disp.visual.backup_npc_saved_fields();
p->disp.visual.extra_model = npc;
p->disp.visual.validation_flags |= 0x02;
}
@@ -1230,7 +1257,7 @@ ChatCommandDefinition cc_item(
} else {
auto l = a.c->require_lobby();
ItemData item = s->parse_item_description(a.c->version(), a.text);
item = s->parse_item_description(a.c->version(), a.text);
item.id = l->generate_item_id(a.c->lobby_client_id);
if ((l->drop_mode == Lobby::DropMode::SERVER_PRIVATE) || (l->drop_mode == Lobby::DropMode::SERVER_DUPLICATE)) {
@@ -1242,7 +1269,7 @@ ChatCommandDefinition cc_item(
}
}
string name = s->describe_item(a.c->version(), item, true);
string name = s->describe_item(a.c->version(), item, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
send_text_message(a.c, "$C7Item created:\n" + name);
co_return;
});
@@ -1304,28 +1331,38 @@ ChatCommandDefinition cc_killcount(
a.check_is_proxy(false);
auto p = a.c->character();
size_t item_index;
try {
item_index = p->inventory.find_equipped_item(EquipSlot::WEAPON);
} catch (const out_of_range&) {
throw precondition_failed("No weapon equipped");
vector<size_t> item_indexes;
for (size_t z = 0; z < p->inventory.num_items; z++) {
const auto& item = p->inventory.items[z];
if (item.is_equipped() && item.data.has_kill_count()) {
item_indexes.emplace_back(z);
}
}
const auto& item = p->inventory.items.at(item_index);
if (!item.data.has_kill_count()) {
throw precondition_failed("Weapon does not\nhave a kill count");
}
if (item_indexes.empty()) {
throw precondition_failed("No equipped items\nhave kill counts");
// Kill counts are only accurate on the server side at all times on BB. On
// other versions, we update the server's view of the client's inventory
// during games, but we can't track kills because the client doesn't inform
// the server whether it counted a kill for any individual enemy. So, on
// non-BB versions, the kill count is accurate at all times in the lobby
// (since kills can't occur there), or at the beginning of a game.
if ((a.c->version() == Version::BB_V4) || !a.c->require_lobby()->is_game()) {
send_text_message_fmt(a.c, "{} kills", item.data.get_kill_count());
} else {
send_text_message_fmt(a.c, "{} kills as of\ngame join", item.data.get_kill_count());
// Kill counts are only accurate on the server side at all times on BB.
// On other versions, we update the server's view of the client's
// inventory during games, but we can't track kills because the client
// doesn't inform the server whether it counted a kill for any
// individual enemy. So, on non-BB versions, the kill count is accurate
// at all times in the lobby (since kills can't occur there), or at the
// beginning of a game.
if ((a.c->version() == Version::BB_V4) || !a.c->require_lobby()->is_game()) {
send_text_message(a.c, "As of now:");
} else {
send_text_message(a.c, "As of game join:");
}
auto s = a.c->require_server_state();
for (size_t z : item_indexes) {
const auto& item = p->inventory.items[z];
string name = s->describe_item(
a.c->version(), item.data, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES | ItemNameIndex::Flag::NAME_ONLY);
send_text_message_fmt(a.c, "{}$C7: {} kills", name, item.data.get_kill_count());
}
}
co_return;
});
@@ -1508,11 +1545,12 @@ ChatCommandDefinition cc_loadchar(
throw precondition_failed("$C7This command cannot\nbe used on a shared\naccount");
}
auto s = a.c->require_server_state();
auto l = a.c->require_lobby();
size_t index = stoull(a.text, nullptr, 0) - 1;
if (index > 15) {
throw precondition_failed("$C6Player index must\nbe in range 1-16");
if (index >= s->num_backup_character_slots) {
throw precondition_failed("$C6Player index must\nbe in range 1-{}", s->num_backup_character_slots);
}
shared_ptr<PSOGCEp3CharacterFile::Character> ep3_char;
@@ -1524,7 +1562,6 @@ ChatCommandDefinition cc_loadchar(
if (a.c->version() == Version::BB_V4) {
// On BB, it suffices to simply send the character file again
auto s = a.c->require_server_state();
send_complete_player_bb(a.c);
send_player_leave_notification(l, a.c->lobby_client_id);
s->send_lobby_join_notifications(l, a.c);
@@ -1576,7 +1613,7 @@ ChatCommandDefinition cc_loadchar(
if (!a.c->login || !a.c->login->xb_license) {
throw runtime_error("XB client is not logged in");
}
PSOXBCharacterFileCharacter xb_char = *a.c->character();
PSOXBCharacterFile::Character xb_char = *a.c->character();
xb_char.guild_card.xb_user_id_high = (a.c->login->xb_license->user_id >> 32) & 0xFFFFFFFF;
xb_char.guild_card.xb_user_id_low = a.c->login->xb_license->user_id & 0xFFFFFFFF;
co_await send_set_extended_player_info(xb_char);
@@ -2332,6 +2369,26 @@ ChatCommandDefinition cc_song(
co_return;
});
ChatCommandDefinition cc_sound(
{"$sound"},
+[](const Args& a) -> asio::awaitable<void> {
bool echo_to_all = (!a.text.empty() && a.text[0] == '!');
uint32_t sound_id = stoul(echo_to_all ? a.text.substr(1) : a.text, nullptr, 16);
// TODO: Using floor is technically incorrect here; it should be area
G_PlaySoundFromPlayer_6xB2 cmd = {{0xB2, 0x03, 0x0000}, static_cast<uint8_t>(a.c->floor), 0x00, a.c->lobby_client_id, sound_id};
if (!echo_to_all) {
send_command_t(a.c, 0x60, 0x00, cmd);
} else if (a.c->proxy_session) {
send_command_t(a.c, 0x60, 0x00, cmd);
send_command_t(a.c->proxy_session->server_channel, 0x60, 0x00, cmd);
} else {
a.check_debug_enabled();
send_command_t(a.c->require_lobby(), 0x60, 0x00, cmd);
}
co_return;
});
ChatCommandDefinition cc_spec(
{"$spec"},
+[](const Args& a) -> asio::awaitable<void> {
@@ -2708,7 +2765,7 @@ ChatCommandDefinition cc_what(
throw precondition_failed("$C4No items are near you");
} else {
auto s = a.c->require_server_state();
string name = s->describe_item(a.c->version(), nearest_fi->data, true);
string name = s->describe_item(a.c->version(), nearest_fi->data, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
send_text_message(a.c, name);
}
co_return;
+24 -12
View File
@@ -261,11 +261,12 @@ void Client::reschedule_save_game_data_timer() {
return;
}
this->save_game_data_timer.expires_after(std::chrono::seconds(60));
this->idle_timeout_timer.async_wait([this](std::error_code ec) {
this->save_game_data_timer.async_wait([this](std::error_code ec) {
if (!ec) {
if (this->character(false)) {
this->save_all();
}
this->reschedule_save_game_data_timer();
}
});
}
@@ -277,9 +278,13 @@ void Client::reschedule_ping_and_timeout_timers() {
this->send_ping_timer.async_wait([this](std::error_code ec) {
if (!ec) {
this->log.info_f("Sending ping command");
// The game doesn't use this timestamp; we only use it for debugging purposes
be_uint64_t timestamp = phosg::now();
this->channel->send(0x1D, 0x00, &timestamp, sizeof(be_uint64_t));
try {
// The game doesn't use this timestamp; we only use it for debugging purposes
be_uint64_t timestamp = phosg::now();
this->channel->send(0x1D, 0x00, &timestamp, sizeof(be_uint64_t));
} catch (const exception& e) {
this->log.warning_f("Failed to send ping: {}", e.what());
}
}
});
}
@@ -854,6 +859,13 @@ void Client::load_all_files() {
if (this->character_data) {
// Clear legacy play_time field
this->character_data->disp.name.clear_after_bytes(0x18);
// Enforce item stack limits, in case they've changed
auto s = this->require_server_state();
auto stack_limits = s->item_stack_limits(this->version());
this->character_data->inventory.enforce_stack_limits(stack_limits);
this->character_data->bank.enforce_stack_limits(stack_limits);
this->login->account->auto_reply_message = this->character_data->auto_reply.decode();
this->login->account->save();
this->last_play_time_update = phosg::now();
@@ -1049,27 +1061,27 @@ void Client::use_character_bank(ssize_t index) {
void Client::print_inventory() const {
auto s = this->require_server_state();
auto p = this->character();
this->log.info_f("[PlayerInventory] Meseta: {}\n", p->disp.stats.meseta);
this->log.info_f("[PlayerInventory] {} items\n", p->inventory.num_items);
this->log.info_f("[PlayerInventory] Meseta: {}", p->disp.stats.meseta);
this->log.info_f("[PlayerInventory] {} items", p->inventory.num_items);
for (size_t x = 0; x < p->inventory.num_items; x++) {
const auto& item = p->inventory.items[x];
auto hex = item.data.hex();
auto name = s->describe_item(this->version(), item.data, false);
this->log.info_f("[PlayerInventory] {:2}: [+{:08X}] {} ({})\n", x, item.flags, hex, name);
auto name = s->describe_item(this->version(), item.data);
this->log.info_f("[PlayerInventory] {:2}: [+{:08X}] {} ({})", x, item.flags, hex, name);
}
}
void Client::print_bank() const {
auto s = this->require_server_state();
auto bank = this->current_bank();
this->log.info_f("[PlayerBank] Meseta: {}\n", bank.meseta);
this->log.info_f("[PlayerBank] {} items\n", bank.num_items);
this->log.info_f("[PlayerBank] Meseta: {}", bank.meseta);
this->log.info_f("[PlayerBank] {} items", bank.num_items);
for (size_t x = 0; x < bank.num_items; x++) {
const auto& item = bank.items[x];
const char* present_token = item.present ? "" : " (missing present flag)";
auto hex = item.data.hex();
auto name = s->describe_item(this->version(), item.data, false);
this->log.info_f("[PlayerBank] {:3}: {} ({}) (x{}){}\n", x, hex, name, item.amount, present_token);
auto name = s->describe_item(this->version(), item.data);
this->log.info_f("[PlayerBank] {:3}: {} ({}) (x{}){}", x, hex, name, item.amount, present_token);
}
}
+15 -14
View File
@@ -50,29 +50,29 @@ public:
SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE = 0x0000000000004000,
SEND_FUNCTION_CALL_NO_CACHE_PATCH = 0x0000000000008000,
CAN_RECEIVE_ENABLE_B2_QUEST = 0x0000000000020000,
AWAITING_ENABLE_B2_QUEST = 0x0000000000040000, // Server-side only
AWAITING_ENABLE_B2_QUEST = 0x0000000000040000,
// State flags
LOADING = 0x0000000000100000, // Server-side only
LOADING_QUEST = 0x0000000000200000, // Server-side only
LOADING_RUNNING_JOINABLE_QUEST = 0x0000000000400000, // Server-side only
LOADING_TOURNAMENT = 0x0000000000800000, // Server-side only
IN_INFORMATION_MENU = 0x0000000001000000, // Server-side only
AT_WELCOME_MESSAGE = 0x0000000002000000, // Server-side only
LOADING = 0x0000000000100000,
LOADING_QUEST = 0x0000000000200000,
LOADING_RUNNING_JOINABLE_QUEST = 0x0000000000400000,
LOADING_TOURNAMENT = 0x0000000000800000,
IN_INFORMATION_MENU = 0x0000000001000000,
AT_WELCOME_MESSAGE = 0x0000000002000000,
SAVE_ENABLED = 0x0000000004000000,
HAS_EP3_CARD_DEFS = 0x0000000008000000,
HAS_EP3_MEDIA_UPDATES = 0x0000000010000000,
HAS_AUTO_PATCHES = 0x0000004000000000,
AT_BANK_COUNTER = 0x0000000080000000, // Server-side only
SHOULD_SEND_ARTIFICIAL_ITEM_STATE = 0x0001000000000000, // Server-side only
SHOULD_SEND_ARTIFICIAL_ENEMY_AND_SET_STATE = 0x0040000000000000, // Server-side only
SHOULD_SEND_ARTIFICIAL_OBJECT_STATE = 0x0080000000000000, // Server-side only
SHOULD_SEND_ARTIFICIAL_FLAG_STATE = 0x0002000000000000, // Server-side only
SHOULD_SEND_ARTIFICIAL_PLAYER_STATES = 0x0200000000000000, // Server-side only
AT_BANK_COUNTER = 0x0000000080000000,
SHOULD_SEND_ARTIFICIAL_ITEM_STATE = 0x0001000000000000,
SHOULD_SEND_ARTIFICIAL_ENEMY_AND_SET_STATE = 0x0040000000000000,
SHOULD_SEND_ARTIFICIAL_OBJECT_STATE = 0x0080000000000000,
SHOULD_SEND_ARTIFICIAL_FLAG_STATE = 0x0002000000000000,
SHOULD_SEND_ARTIFICIAL_PLAYER_STATES = 0x0200000000000000,
SHOULD_SEND_ENABLE_SAVE = 0x0004000000000000,
SWITCH_ASSIST_ENABLED = 0x0000000100000000,
IS_CLIENT_CUSTOMIZATION = 0x0100000000000000,
EP3_ALLOW_6xBC = 0x1000000000000000, // Server-side only
EP3_ALLOW_6xBC = 0x1000000000000000,
// Cheat mode and option flags
INFINITE_HP_ENABLED = 0x0000000200000000,
@@ -80,6 +80,7 @@ public:
DEBUG_ENABLED = 0x0000000800000000,
ITEM_DROP_NOTIFICATIONS_1 = 0x0010000000000000,
ITEM_DROP_NOTIFICATIONS_2 = 0x0020000000000000,
HAS_ENEMY_DAMAGE_SYNC_PATCH = 0x2000000000000000, // Must be same as in EnemyDamageSync*.s
// Proxy option flags
PROXY_SAVE_FILES = 0x0000001000000000,
+67 -32
View File
@@ -807,6 +807,20 @@ struct C_WriteFileConfirmation_V3_BB_13_A7 {
using S_Reconnect_19 = S_ReconnectT<le_uint16_t>;
check_struct_size(S_Reconnect_19, 8);
// Sylverant implements an IPv6 version of this command, but it's not obvious
// why. IPv6 technically did exist as a draft standard at the time of PSO's
// development, but it wasn't widely used until over a decade later. IPv6
// support is not implemented in any version of the PSO client that I've seen,
// but we implement Sylverant's version of this command anyway because newserv
// may connect to Sylverant via IPv6 when using the proxy. Sylverant sends the
// value 6 in header.flag in this case, presumably to indicate the protocol.
struct S_ReconnectIPv6_Extension_19 {
parray<uint8_t, 0x10> address;
le_uint16_t port = 0;
le_uint16_t unused = 0;
} __packed_ws__(S_ReconnectIPv6_Extension_19, 0x14);
// Because PSO PC and some versions of PSO DC/GC use the same port but different
// protocols, we use a specially-crafted 19 command to send them to two
// different ports depending on the client version. I first saw this technique
@@ -876,10 +890,8 @@ struct S_ReconnectSplit_19 {
// it's not clear if this is accurate. At least, BB US v1.24.3 and later do not
// support this command.
// 0022: GameGuard check (BB)
// Command 0022 is a 16-byte challenge (sent in the data field) using the
// following structure.
// 0022: GameGuard challenge/response (BB)
// This command is not valid on BB Trial Edition.
struct SC_GameGuardCheck_BB_0022 {
parray<le_uint32_t, 4> data;
@@ -890,11 +902,13 @@ struct SC_GameGuardCheck_BB_0022 {
// the returned timestamp is before the previous timestamp returned, but not by
// too much - it seems the game only considers deltas between 3 seconds and 30
// minutes suspicious for these purposes.
// This command is not valid on BB Trial Edition.
// 23 (S->C): Momoka Item Exchange result (BB)
// Sent in response to a 6xD9 command from the client.
// header.flag indicates if an item was exchanged: 0 means success, 1 means
// failure.
// This command is not valid on BB Trial Edition.
// 24 (S->C): Secret Lottery Ticket exchange result (BB)
// Sent in response to a 6xDE command from the client.
@@ -904,6 +918,7 @@ struct SC_GameGuardCheck_BB_0022 {
// header.flag indicates whether the client had any Secret Lottery Tickets in
// their inventory (and hence could participate): 0 means success, 1 means
// failure. However, this value is unused by the client.
// This command is not valid on BB Trial Edition.
struct S_ExchangeSecretLotteryTicketResult_BB_24 {
le_uint16_t label = 0;
@@ -914,8 +929,9 @@ struct S_ExchangeSecretLotteryTicketResult_BB_24 {
// 25 (S->C): Gallon's Plan result (BB)
// Sent in response to a 6xE1 command from the client.
// The client sets the quest registers reg_num1 to reg_value1 and reg_num2 to
// reg_value2, then starts a new quest thread at the specified label.
// The client sets the quest registers reg_num1 to value1 and reg_num2 to
// value2, then starts a new quest thread at the specified label.
// This command is not valid on BB Trial Edition.
struct S_GallonPlanResult_BB_25 {
le_uint16_t label = 0;
@@ -2000,8 +2016,9 @@ struct C_LoginExtended_PC_9D : C_Login_DC_PC_GC_9D {
SC_MeetUserExtension_PC_BB extension;
} __packed_ws__(C_LoginExtended_PC_9D, 0x14C);
// 9E (C->S): Log in with client config (V3/BB)
// Not used on GC Episodes 1&2 Trial Edition.
// 9E (C->S): Log in with client config (PC/V3/BB)
// Not used on GC Episodes 1&2 Trial Edition, nor on v1 or most v2 versions.
// Of all pre-v3 versions, only the latest version of PCv2 appears to use this.
// The extended version of this command is used in the same circumstances as
// when PSO PC uses the extended version of the 9D command.
// PSO XB does not send the client config (security data) in the 9E command,
@@ -2009,11 +2026,13 @@ struct C_LoginExtended_PC_9D : C_Login_DC_PC_GC_9D {
// retrieve the client config.
// header.flag is 1 if the client has UDP disabled.
struct C_Login_GC_9E : C_Login_DC_PC_GC_9D {
struct C_Login_PC_GC_9E : C_Login_DC_PC_GC_9D {
parray<uint8_t, 0x20> client_config;
} __packed_ws__(C_Login_GC_9E, 0xE8);
struct C_LoginExtended_GC_9E : C_Login_GC_9E {
} __packed_ws__(C_Login_PC_GC_9E, 0xE8);
struct C_LoginExtended_PC_9E : C_Login_PC_GC_9E {
SC_MeetUserExtension_PC_BB extension;
} __packed_ws__(C_LoginExtended_PC_9E, 0x16C);
struct C_LoginExtended_GC_9E : C_Login_PC_GC_9E {
SC_MeetUserExtension_DC_V3 extension;
} __packed_ws__(C_LoginExtended_GC_9E, 0x14C);
@@ -2051,12 +2070,13 @@ struct C_LoginExtended_BB_9E {
/* 0170 */
} __packed_ws__(C_LoginExtended_BB_9E, 0x170);
// 9F (S->C): Request client config / security data (V3/BB)
// This command is not valid on PSO GC Episodes 1&2 Trial Edition, nor any
// pre-V3 PSO versions. Client will respond with a 9F command.
// 9F (S->C): Request client config / security data (PC/V3/BB)
// This command is not valid on PSO GC Episodes 1&2 Trial Edition nor on any
// other pre-v3 versions, except the latest PC v2 version, which does have it.
// Client will respond with a 9F command.
// No arguments
// 9F (C->S): Client config / security data response (V3/BB)
// 9F (C->S): Client config / security data response (PC/V3/BB)
// The data is opaque to the client, as described at the top of this file.
// On BB, this command does not work during the data server phase.
@@ -3789,7 +3809,8 @@ struct S_SetShutdownCommand_BB_01EF {
// F0 (S->C): Force update player lobby data (BB)
// Format is PlayerLobbyDataBB (in PlayerSubordinates.hh). This command
// overwrites the lobby data for the player given by .client_id without
// reloading the game or lobby.
// reloading the game or lobby. This command is not valid on PSOBB Trial
// Edition.
// This command probably exists to handle cases like the following:
// 1. Player A is in a team and is not the team master. Player A creates a game.
@@ -4012,17 +4033,19 @@ struct G_SymbolChat_6x07 {
// 6x08: Invalid subcommand
// 6x09: Unknown
// 6x09: Kill enemy (broken/unused)
// header.entity_id is expected to be an enemy ID, but is also expected to be
// in the range [0x00, 0x80) since it writes to an array of 0x80 entries. This
// duality makes no sense because enemy IDs are greater than or equal to
// 0x1000, so any valid enemy ID would be far outside the array's range, and
// the write is not bounds-checked. For this reason, newserv unconditionally
// blocks this command.
// in the range [0x00, 0x80) since the command handler writes to an array of
// 0x80 entries. This duality is nonsense because enemy IDs are greater than or
// equal to 0x1000, so any valid enemy ID would be far outside the array's
// range. newserv unconditionally blocks this command because it appears never
// to be used, and the array write is not bounds-checked, so it could be used
// to cause undefined behavior on other clients. It seems that this broken
// logic predates even DC NTE.
struct G_Unknown_6x09 {
struct G_LegacyKillEnemy_6x09 {
G_EntityIDHeader header;
} __packed_ws__(G_Unknown_6x09, 4);
} __packed_ws__(G_LegacyKillEnemy_6x09, 4);
// 6x0A: Update enemy state
// In Ultimate mode, the low 6 bits of game_flags are ignored, and 6x9C is used
@@ -4584,6 +4607,8 @@ struct G_PlayerDied_6x4D {
} __packed_ws__(G_PlayerDied_6x4D, 8);
// 6x4E: Player is dead can be revived (protected on V3/V4)
// This command creates the particle effect that Reverser and Moon Atomizers
// can target.
struct G_PlayerRevivable_6x4E {
G_ClientIDHeader header;
@@ -4982,9 +5007,7 @@ struct G_6x70_Base_DCNTE {
/* 0002 */ le_uint16_t room_id = 0;
/* 0004 */ le_uint32_t flags1 = 0;
/* 0008 */ VectorXYZF pos;
/* 0014 */ le_uint32_t angle_x = 0;
/* 0018 */ le_uint32_t angle_y = 0;
/* 001C */ le_uint32_t angle_z = 0;
/* 0014 */ VectorXYZI angle;
/* 0020 */ le_uint16_t unknown_a3a = 0;
/* 0022 */ le_uint16_t current_hp = 0;
} __packed_ws__(G_6x70_Base_DCNTE, 0x24);
@@ -5188,9 +5211,9 @@ struct G_Unknown_6x78 {
struct G_GogoBall_6x79 {
G_UnusedHeader header;
le_uint32_t unknown_a1 = 0;
le_uint32_t unknown_a2 = 0;
le_uint32_t angle = 0;
VectorXZF ball_pos;
uint8_t unknown_a5 = 0;
uint8_t use_missile_sound = 0;
parray<uint8_t, 3> unused;
} __packed_ws__(G_GogoBall_6x79, 0x18);
@@ -6366,7 +6389,7 @@ struct G_SetMesetaSlotPrizeResult_BB_6xE3 {
ItemData item;
} __packed_ws__(G_SetMesetaSlotPrizeResult_BB_6xE3, 0x18);
// 6xE4: Invalid subcommand
// 6xE4: Invalid subcommand (but used as an extension; see end of this file)
// 6xE5: Invalid subcommand
// 6xE6: Invalid subcommand
// 6xE7: Invalid subcommand
@@ -7431,4 +7454,16 @@ struct G_RejectBattleStartRequest_Ep3_6xB4x53 {
// Requested with the GetExtendedPlayerInfo patch. Format depends on version:
// DC v2: PSODCV2CharacterFile
// GC v3: PSOGCCharacterFile::Character
// XB v3: PSOXBCharacterFileCharacter
// XB v3: PSOXBCharacterFile::Character
// 6xE4: Increment enemy damage threshold
// This command increments or decrements the amount of damage an enemy has
// sustained. This replaces the use of total_damage in 6x0A to update enemy HP.
struct G_IncrementEnemyDamage_Extension_6xE4 {
G_EntityIDHeader header = {0xE4, sizeof(G_IncrementEnemyDamage_Extension_6xE4) / 4, 0x0000};
le_int16_t hit_amount = 0;
le_uint16_t total_damage_before_hit = 0;
le_uint16_t current_hp_before_hit = 0;
le_uint16_t max_hp = 0;
} __packed_ws__(G_IncrementEnemyDamage_Extension_6xE4, 0x0C);
+171 -3
View File
@@ -128,8 +128,15 @@ CommonItemSet::Table::Table(const phosg::JSON& json, Episode episode)
for (size_t z = 0; z < 0x64; z++) {
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (Episode episode : episodes) {
auto types = enemy_types_for_rare_table_index(episode, z);
vector<string> names;
if (types.empty()) {
names.emplace_back(std::format("{}:!{:02X}", abbreviation_for_episode(episode), z));
}
for (auto type : enemy_types_for_rare_table_index(episode, z)) {
string name = std::format("{}:{}", abbreviation_for_episode(episode), phosg::name_for_enum(type));
names.emplace_back(std::format("{}:{}", abbreviation_for_episode(episode), phosg::name_for_enum(type)));
}
for (const auto& name : names) {
from_json_into(*enemy_meseta_ranges_json.at(name), this->enemy_meseta_ranges[z]);
this->enemy_type_drop_probs[z] = enemy_type_drop_probs_json.at(name)->as_int();
this->enemy_item_classes[z] = enemy_item_classes_json.at(name)->as_int();
@@ -336,6 +343,122 @@ void CommonItemSet::Table::print(FILE* stream) const {
}
}
void CommonItemSet::Table::print_diff(FILE* stream, const Table& other) const {
if (this->episode != other.episode) {
phosg::fwrite_fmt(stream, "> Episode: {} -> {}\n", name_for_episode(this->episode), name_for_episode(other.episode));
}
if (this->base_weapon_type_prob_table != other.base_weapon_type_prob_table) {
phosg::fwrite_fmt(stream, "> base_weapon_type_prob_table: {} -> {}\n",
phosg::format_data_string(&this->base_weapon_type_prob_table, sizeof(this->base_weapon_type_prob_table)),
phosg::format_data_string(&other.base_weapon_type_prob_table, sizeof(other.base_weapon_type_prob_table)));
}
if (this->subtype_base_table != other.subtype_base_table) {
phosg::fwrite_fmt(stream, "> subtype_base_table: {} -> {}\n",
phosg::format_data_string(&this->subtype_base_table, sizeof(this->subtype_base_table)),
phosg::format_data_string(&other.subtype_base_table, sizeof(other.subtype_base_table)));
}
if (this->subtype_area_length_table != other.subtype_area_length_table) {
phosg::fwrite_fmt(stream, "> subtype_area_length_table: {} -> {}\n",
phosg::format_data_string(&this->subtype_area_length_table, sizeof(this->subtype_area_length_table)),
phosg::format_data_string(&other.subtype_area_length_table, sizeof(other.subtype_area_length_table)));
}
if (this->grind_prob_table != other.grind_prob_table) {
phosg::fwrite_fmt(stream, "> grind_prob_table: {} -> {}\n",
phosg::format_data_string(&this->grind_prob_table, sizeof(this->grind_prob_table)),
phosg::format_data_string(&other.grind_prob_table, sizeof(other.grind_prob_table)));
}
if (this->armor_shield_type_index_prob_table != other.armor_shield_type_index_prob_table) {
phosg::fwrite_fmt(stream, "> armor_shield_type_index_prob_table: {} -> {}\n",
phosg::format_data_string(&this->armor_shield_type_index_prob_table, sizeof(this->armor_shield_type_index_prob_table)),
phosg::format_data_string(&other.armor_shield_type_index_prob_table, sizeof(other.armor_shield_type_index_prob_table)));
}
if (this->armor_slot_count_prob_table != other.armor_slot_count_prob_table) {
phosg::fwrite_fmt(stream, "> armor_slot_count_prob_table: {} -> {}\n",
phosg::format_data_string(&this->armor_slot_count_prob_table, sizeof(this->armor_slot_count_prob_table)),
phosg::format_data_string(&other.armor_slot_count_prob_table, sizeof(other.armor_slot_count_prob_table)));
}
if (this->enemy_meseta_ranges != other.enemy_meseta_ranges) {
phosg::fwrite_fmt(stream, "> enemy_meseta_ranges: {} -> {}\n",
phosg::format_data_string(&this->enemy_meseta_ranges, sizeof(this->enemy_meseta_ranges)),
phosg::format_data_string(&other.enemy_meseta_ranges, sizeof(other.enemy_meseta_ranges)));
}
if (this->enemy_type_drop_probs != other.enemy_type_drop_probs) {
phosg::fwrite_fmt(stream, "> enemy_type_drop_probs: {} -> {}\n",
phosg::format_data_string(&this->enemy_type_drop_probs, sizeof(this->enemy_type_drop_probs)),
phosg::format_data_string(&other.enemy_type_drop_probs, sizeof(other.enemy_type_drop_probs)));
}
if (this->enemy_item_classes != other.enemy_item_classes) {
phosg::fwrite_fmt(stream, "> enemy_item_classes: {} -> {}\n",
phosg::format_data_string(&this->enemy_item_classes, sizeof(this->enemy_item_classes)),
phosg::format_data_string(&other.enemy_item_classes, sizeof(other.enemy_item_classes)));
}
if (this->box_meseta_ranges != other.box_meseta_ranges) {
phosg::fwrite_fmt(stream, "> box_meseta_ranges: {} -> {}\n",
phosg::format_data_string(&this->box_meseta_ranges, sizeof(this->box_meseta_ranges)),
phosg::format_data_string(&other.box_meseta_ranges, sizeof(other.box_meseta_ranges)));
}
if (this->has_rare_bonus_value_prob_table != other.has_rare_bonus_value_prob_table) {
phosg::fwrite_fmt(stream, "> Has rare bonus value prob table: {} -> {}\n",
this->has_rare_bonus_value_prob_table ? "true" : "false",
other.has_rare_bonus_value_prob_table ? "true" : "false");
}
if (this->bonus_value_prob_table != other.bonus_value_prob_table) {
phosg::fwrite_fmt(stream, "> bonus_value_prob_table: {} -> {}\n",
phosg::format_data_string(&this->bonus_value_prob_table, sizeof(this->bonus_value_prob_table)),
phosg::format_data_string(&other.bonus_value_prob_table, sizeof(other.bonus_value_prob_table)));
}
if (this->nonrare_bonus_prob_spec != other.nonrare_bonus_prob_spec) {
phosg::fwrite_fmt(stream, "> nonrare_bonus_prob_spec: {} -> {}\n",
phosg::format_data_string(&this->nonrare_bonus_prob_spec, sizeof(this->nonrare_bonus_prob_spec)),
phosg::format_data_string(&other.nonrare_bonus_prob_spec, sizeof(other.nonrare_bonus_prob_spec)));
}
if (this->bonus_type_prob_table != other.bonus_type_prob_table) {
phosg::fwrite_fmt(stream, "> bonus_type_prob_table: {} -> {}\n",
phosg::format_data_string(&this->bonus_type_prob_table, sizeof(this->bonus_type_prob_table)),
phosg::format_data_string(&other.bonus_type_prob_table, sizeof(other.bonus_type_prob_table)));
}
if (this->special_mult != other.special_mult) {
phosg::fwrite_fmt(stream, "> special_mult: {} -> {}\n",
phosg::format_data_string(&this->special_mult, sizeof(this->special_mult)),
phosg::format_data_string(&other.special_mult, sizeof(other.special_mult)));
}
if (this->special_percent != other.special_percent) {
phosg::fwrite_fmt(stream, "> special_percent: {} -> {}\n",
phosg::format_data_string(&this->special_percent, sizeof(this->special_percent)),
phosg::format_data_string(&other.special_percent, sizeof(other.special_percent)));
}
if (this->tool_class_prob_table != other.tool_class_prob_table) {
phosg::fwrite_fmt(stream, "> tool_class_prob_table: {} -> {}\n",
phosg::format_data_string(&this->tool_class_prob_table, sizeof(this->tool_class_prob_table)),
phosg::format_data_string(&other.tool_class_prob_table, sizeof(other.tool_class_prob_table)));
}
if (this->technique_index_prob_table != other.technique_index_prob_table) {
phosg::fwrite_fmt(stream, "> technique_index_prob_table: {} -> {}\n",
phosg::format_data_string(&this->technique_index_prob_table, sizeof(this->technique_index_prob_table)),
phosg::format_data_string(&other.technique_index_prob_table, sizeof(other.technique_index_prob_table)));
}
if (this->technique_level_ranges != other.technique_level_ranges) {
phosg::fwrite_fmt(stream, "> technique_level_ranges: {} -> {}\n",
phosg::format_data_string(&this->technique_level_ranges, sizeof(this->technique_level_ranges)),
phosg::format_data_string(&other.technique_level_ranges, sizeof(other.technique_level_ranges)));
}
if (this->armor_or_shield_type_bias != other.armor_or_shield_type_bias) {
phosg::fwrite_fmt(stream, "> Armor/shield type bias: {} -> {}\n",
this->armor_or_shield_type_bias ? "true" : "false",
other.armor_or_shield_type_bias ? "true" : "false");
}
if (this->unit_max_stars_table != other.unit_max_stars_table) {
phosg::fwrite_fmt(stream, "> unit_max_stars_table: {} -> {}\n",
phosg::format_data_string(&this->unit_max_stars_table, sizeof(this->unit_max_stars_table)),
phosg::format_data_string(&other.unit_max_stars_table, sizeof(other.unit_max_stars_table)));
}
if (this->box_item_class_prob_table != other.box_item_class_prob_table) {
phosg::fwrite_fmt(stream, "> box_item_class_prob_table: {} -> {}\n",
phosg::format_data_string(&this->box_item_class_prob_table, sizeof(this->box_item_class_prob_table)),
phosg::format_data_string(&other.box_item_class_prob_table, sizeof(other.box_item_class_prob_table)));
}
}
phosg::JSON CommonItemSet::Table::json() const {
phosg::JSON enemy_meseta_ranges_json = phosg::JSON::dict();
phosg::JSON enemy_type_drop_probs_json = phosg::JSON::dict();
@@ -343,8 +466,16 @@ phosg::JSON CommonItemSet::Table::json() const {
for (size_t z = 0; z < 0x64; z++) {
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (Episode episode : episodes) {
for (auto type : enemy_types_for_rare_table_index(episode, z)) {
string name = std::format("{}:{}", abbreviation_for_episode(episode), phosg::name_for_enum(type));
auto types = enemy_types_for_rare_table_index(episode, z);
vector<string> names;
if (types.empty()) {
names.emplace_back(std::format("{}:!{:02X}", abbreviation_for_episode(episode), z));
} else {
for (auto type : types) {
names.emplace_back(std::format("{}:{}", abbreviation_for_episode(episode), phosg::name_for_enum(type)));
}
}
for (const auto& name : names) {
enemy_meseta_ranges_json.emplace(name, to_json(this->enemy_meseta_ranges[z]));
enemy_type_drop_probs_json.emplace(name, this->enemy_type_drop_probs[z]);
enemy_item_classes_json.emplace(name, this->enemy_item_classes[z]);
@@ -424,6 +555,43 @@ void CommonItemSet::print(FILE* stream) const {
}
}
void CommonItemSet::print_diff(FILE* stream, const CommonItemSet& other) const {
static const array<GameMode, 4> modes = {GameMode::NORMAL, GameMode::BATTLE, GameMode::CHALLENGE, GameMode::SOLO};
for (const auto& mode : modes) {
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (const auto& episode : episodes) {
for (uint8_t difficulty = 0; difficulty < 4; difficulty++) {
for (uint8_t section_id = 0; section_id < 10; section_id++) {
shared_ptr<const Table> this_table;
shared_ptr<const Table> other_table;
try {
this_table = this->get_table(episode, mode, difficulty, section_id);
} catch (const runtime_error&) {
}
try {
other_table = other.get_table(episode, mode, difficulty, section_id);
} catch (const runtime_error&) {
}
if (!this_table && !other_table) {
continue;
} else if (!this_table) {
phosg::fwrite_fmt(stream, "> Table present in other but not this: {} {} {} {}\n",
name_for_mode(mode), name_for_episode(episode), name_for_difficulty(difficulty), name_for_section_id(section_id));
} else if (!other_table) {
phosg::fwrite_fmt(stream, "> Table present in this but not other: {} {} {} {}\n",
name_for_mode(mode), name_for_episode(episode), name_for_difficulty(difficulty), name_for_section_id(section_id));
} else if (*this_table != *other_table) {
phosg::fwrite_fmt(stream, "> Tables do not match: {} {} {} {}\n",
name_for_mode(mode), name_for_episode(episode), name_for_difficulty(difficulty), name_for_section_id(section_id));
this_table->print_diff(stream, *other_table);
}
}
}
}
}
}
CommonItemSet::Table::Table(const phosg::StringReader& r, bool is_big_endian, bool is_v3, Episode episode)
: episode(episode) {
if (is_big_endian) {
+11
View File
@@ -18,10 +18,16 @@ public:
Table(const phosg::JSON& json, Episode episode);
Table(const phosg::StringReader& r, bool big_endian, bool is_v3, Episode episode);
bool operator==(const Table& other) const = default;
bool operator!=(const Table& other) const = default;
template <typename IntT>
struct Range {
IntT min;
IntT max;
bool operator==(const Range& other) const = default;
bool operator!=(const Range& other) const = default;
} __attribute__((packed));
Episode episode;
@@ -50,6 +56,7 @@ public:
phosg::JSON json() const;
void print(FILE* stream) const;
void print_diff(FILE* stream, const Table& other) const;
private:
template <bool BE>
@@ -261,9 +268,13 @@ public:
check_struct_size(OffsetsBE, 0x54);
};
bool operator==(const CommonItemSet& other) const = default;
bool operator!=(const CommonItemSet& other) const = default;
std::shared_ptr<const Table> get_table(Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const;
phosg::JSON json() const;
void print(FILE* stream) const;
void print_diff(FILE* stream, const CommonItemSet& other) const;
protected:
CommonItemSet() = default;
+1 -1
View File
@@ -184,7 +184,7 @@ void DownloadSession::send_93_9D_9E(bool extended) {
ret.access_key2 = ret.access_key;
ret.login_character_name.encode(this->character->disp.name.decode());
ret.client_config = this->client_config;
this->channel->send(0x9E, 0x01, &ret, extended ? sizeof(ret) : sizeof(C_Login_GC_9E));
this->channel->send(0x9E, 0x01, &ret, extended ? sizeof(ret) : sizeof(C_Login_PC_GC_9E));
} else if (this->version == Version::XB_V3) {
C_LoginExtended_XB_9E ret;
+27
View File
@@ -198,6 +198,33 @@ const vector<EnemyType>& enemy_types_for_rare_table_index(Episode episode, uint8
}
}
const vector<EnemyType>& enemy_types_for_battle_param_index(Episode episode, uint8_t bp_index) {
const auto& generate_table = +[](Episode episode) -> vector<vector<EnemyType>> {
vector<vector<EnemyType>> ret;
for (const auto& def : type_defs) {
if (def.valid_in_episode(episode) && (def.bp_index != 0xFF)) {
if (def.bp_index >= ret.size()) {
ret.resize(def.bp_index + 1);
}
ret[def.bp_index].emplace_back(def.type);
}
}
return ret;
};
static array<vector<vector<EnemyType>>, 5> data;
auto& ret = data.at(static_cast<size_t>(episode));
if (ret.empty()) {
ret = generate_table(episode);
}
try {
return ret.at(bp_index);
} catch (const out_of_range&) {
static const vector<EnemyType> empty_vec;
return empty_vec;
}
}
EnemyType EnemyTypeDefinition::rare_type(Episode episode, uint8_t event, uint8_t floor) const {
switch (this->type) {
case EnemyType::HILDEBEAR:
+1
View File
@@ -181,3 +181,4 @@ template <>
EnemyType phosg::enum_for_name<EnemyType>(const char* name);
const std::vector<EnemyType>& enemy_types_for_rare_table_index(Episode episode, uint8_t rt_index);
const std::vector<EnemyType>& enemy_types_for_battle_param_index(Episode episode, uint8_t bp_index);
+13
View File
@@ -1177,6 +1177,19 @@ void PlayerConfig::encrypt(uint8_t basis) {
this->basis = basis;
}
bool PlayerConfig::card_count_checksums_correct() const {
for (size_t z = 0; z < this->card_count_checksums.size(); z++) {
uint16_t checksum_value = 0;
for (size_t w = 0; w < 20; w++) {
checksum_value += reinterpret_cast<const uint8_t*>(&this->card_counts)[z * 50 + w];
}
if (this->card_count_checksums[z] != checksum_value) {
return false;
}
}
return true;
}
PlayerConfigNTE::PlayerConfigNTE(const PlayerConfig& config)
: rank_text(config.rank_text),
unknown_a1(config.unknown_a1),
+8 -4
View File
@@ -605,9 +605,10 @@ struct CardDefinition {
// actions, and assist cards have 1 here.
/* 008F */ uint8_t cannot_attack;
/* 0090 */ uint8_t unused3;
// If cannot_drop is 0, this card can't appear in post-battle rewards. A
// value of 0 here also prevents the card from being used as a God Whim
// random assist.
// If cannot_drop is 1, this card can't appear in post-battle rewards and is
// considered unobtainable by players, so the game will remove it from the
// player's collection if they have any copies of it. A value of 1 here also
// prevents the card from being used as a God Whim random assist.
/* 0091 */ uint8_t cannot_drop;
// This criterion code specifies who can use the card, and when it can be
// used. This specifies which Hero-side SCs can use which items, for example,
@@ -864,7 +865,8 @@ struct PlayerConfig {
/* 0138:---- */ PlayerRecordsBattleBE unused_offline_records;
/* 0150:---- */ parray<uint8_t, 4> unknown_a4;
// The PlayerDataSegment structure begins here. In newserv, we combine this
// structure into PlayerConfig since the two are always used together.
// structure into PlayerConfig since the two are always used together on the
// server side.
/* 0154:0000 */ uint8_t is_encrypted;
/* 0155:0001 */ uint8_t basis;
/* 0156:0002 */ parray<uint8_t, 2> unused;
@@ -937,6 +939,8 @@ struct PlayerConfig {
void decrypt();
void encrypt(uint8_t basis);
bool card_count_checksums_correct() const;
} __packed_ws__(PlayerConfig, 0x2350);
struct PlayerConfigNTE {
+162 -84
View File
@@ -96,11 +96,9 @@ string CompiledFunctionCode::generate_client_command(
size_t suffix_size,
uint32_t override_relocations_offset) const {
if (this->arch == Architecture::POWERPC) {
return this->generate_client_command_t<true>(
label_writes, suffix_data, suffix_size, override_relocations_offset);
return this->generate_client_command_t<true>(label_writes, suffix_data, suffix_size, override_relocations_offset);
} else if ((this->arch == Architecture::X86) || (this->arch == Architecture::SH4)) {
return this->generate_client_command_t<false>(
label_writes, suffix_data, suffix_size, override_relocations_offset);
return this->generate_client_command_t<false>(label_writes, suffix_data, suffix_size, override_relocations_offset);
} else {
throw logic_error("invalid architecture");
}
@@ -110,18 +108,12 @@ bool CompiledFunctionCode::is_big_endian() const {
return this->arch == Architecture::POWERPC;
}
shared_ptr<CompiledFunctionCode> compile_function_code(
static vector<shared_ptr<CompiledFunctionCode>> compile_function_code(
CompiledFunctionCode::Architecture arch,
const string& function_directory,
const string& system_directory,
const string& name,
const string& text) {
auto ret = make_shared<CompiledFunctionCode>();
ret->arch = arch;
ret->short_name = name;
ret->index = 0;
ret->hide_from_patches_menu = false;
unordered_set<string> get_include_stack;
function<string(const string&)> get_include = [&](const string& name) -> string {
const char* arch_name_token;
@@ -177,56 +169,137 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
throw runtime_error("data not found for include: " + name + " (from " + asm_filename + " or " + bin_filename + ")");
};
ResourceDASM::EmulatorBase::AssembleResult assembled;
if (arch == CompiledFunctionCode::Architecture::POWERPC) {
assembled = ResourceDASM::PPC32Emulator::assemble(text, get_include);
} else if (arch == CompiledFunctionCode::Architecture::X86) {
assembled = ResourceDASM::X86Emulator::assemble(text, get_include);
} else if (arch == CompiledFunctionCode::Architecture::SH4) {
assembled = ResourceDASM::SH4Emulator::assemble(text, get_include);
} else {
throw runtime_error("invalid architecture");
}
ret->code = std::move(assembled.code);
ret->label_offsets = std::move(assembled.label_offsets);
for (const auto& it : assembled.metadata_keys) {
if (it.first == "hide_from_patches_menu") {
ret->hide_from_patches_menu = true;
} else if (it.first == "index") {
if (it.second.size() != 1) {
throw runtime_error("invalid index value in .meta directive");
// Handle VERS tokens
vector<uint32_t> specific_versions;
auto lines = phosg::split(text, '\n');
for (auto& line : lines) {
if (line.starts_with(".versions ")) {
if (!specific_versions.empty()) {
throw std::runtime_error("multiple .versions directives in file");
}
ret->index = it.second[0];
} else if (it.first == "name") {
ret->long_name = it.second;
} else if (it.first == "description") {
ret->description = it.second;
} else {
throw runtime_error("unknown metadata key: " + it.first);
for (auto& vers_token : phosg::split(line.substr(10), ' ')) {
phosg::strip_whitespace(vers_token);
if (vers_token.empty()) {
continue;
}
if (vers_token.size() != 4) {
throw std::runtime_error("invalid token in .version directive: " + vers_token);
}
specific_versions.emplace_back(*reinterpret_cast<const be_uint32_t*>(vers_token.data()));
}
line.clear();
}
}
set<uint32_t> reloc_indexes;
for (const auto& it : ret->label_offsets) {
if (it.first.starts_with("reloc")) {
reloc_indexes.emplace(it.second / 4);
// Preprocess <VERS> tokens in the text if a .versions directive was given
vector<string> version_texts;
if (specific_versions.empty()) {
specific_versions.emplace_back(0);
version_texts.emplace_back(text);
} else {
vector<deque<string>> version_lines;
version_lines.resize(specific_versions.size());
size_t line_num = 1;
for (const auto& line : lines) {
size_t vers_offset = line.find("<VERS ");
if (vers_offset == string::npos) {
for (auto& lines : version_lines) {
lines.emplace_back(line);
}
} else {
for (size_t vers_index = 0; vers_index < specific_versions.size(); vers_index++) {
string version_line = line;
size_t vers_offset = line.find("<VERS ");
while (vers_offset != string::npos) {
size_t end_offset = version_line.find('>', vers_offset + 6);
if (end_offset == string::npos) {
throw runtime_error(std::format("(line {}) unterminated <VERS> replacement", line_num));
}
auto tokens = phosg::split(version_line.substr(vers_offset + 6, end_offset - vers_offset - 6), ' ');
if (tokens.size() != specific_versions.size()) {
throw runtime_error(std::format("(line {}) invalid <VERS> replacement", line_num));
}
version_line = version_line.substr(0, vers_offset) + tokens.at(vers_index) + version_line.substr(end_offset + 1);
vers_offset = version_line.find("<VERS ");
}
version_lines[vers_index].emplace_back(version_line);
}
}
line_num++;
}
for (const auto& lines : version_lines) {
version_texts.emplace_back(phosg::join(lines, "\n"));
}
}
try {
ret->entrypoint_offset_offset = ret->label_offsets.at("entry_ptr");
} catch (const out_of_range&) {
throw runtime_error("code does not contain entry_ptr label");
}
vector<shared_ptr<CompiledFunctionCode>> ret;
for (size_t vers_index = 0; vers_index < specific_versions.size(); vers_index++) {
uint32_t specific_version = specific_versions[vers_index];
const auto& version_text = version_texts.at(vers_index);
uint32_t prev_index = 0;
for (const auto& it : reloc_indexes) {
uint32_t delta = it - prev_index;
if (delta > 0xFFFF) {
throw runtime_error("relocation delta too far away");
try {
ResourceDASM::EmulatorBase::AssembleResult assembled;
if (arch == CompiledFunctionCode::Architecture::POWERPC) {
assembled = ResourceDASM::PPC32Emulator::assemble(version_text, get_include);
} else if (arch == CompiledFunctionCode::Architecture::X86) {
assembled = ResourceDASM::X86Emulator::assemble(version_text, get_include);
} else if (arch == CompiledFunctionCode::Architecture::SH4) {
assembled = ResourceDASM::SH4Emulator::assemble(version_text, get_include);
} else {
throw runtime_error("invalid architecture");
}
auto compiled = ret.emplace_back(make_shared<CompiledFunctionCode>());
compiled->arch = arch;
compiled->short_name = name;
compiled->specific_version = specific_version;
compiled->code = std::move(assembled.code);
compiled->label_offsets = std::move(assembled.label_offsets);
for (const auto& it : assembled.metadata_keys) {
if (it.first == "hide_from_patches_menu") {
compiled->hide_from_patches_menu = true;
} else if (it.first == "name") {
compiled->long_name = it.second;
} else if (it.first == "description") {
compiled->description = it.second;
} else if (it.first == "client_flag") {
compiled->client_flag = stoull(it.second, nullptr, 0);
} else {
throw runtime_error("unknown metadata key: " + it.first);
}
}
set<uint32_t> reloc_indexes;
for (const auto& it : compiled->label_offsets) {
if (it.first.starts_with("reloc")) {
reloc_indexes.emplace(it.second / 4);
}
}
try {
compiled->entrypoint_offset_offset = compiled->label_offsets.at("entry_ptr");
} catch (const out_of_range&) {
throw runtime_error("code does not contain entry_ptr label");
}
uint32_t prev_index = 0;
for (const auto& it : reloc_indexes) {
uint32_t delta = it - prev_index;
if (delta > 0xFFFF) {
throw runtime_error("relocation delta too far away");
}
compiled->relocation_deltas.emplace_back(delta);
prev_index = it;
}
} catch (const exception& e) {
string version_str = specific_version ? (" (" + str_for_specific_version(specific_version) + ")") : "";
function_compiler_log.warning_f("Failed to compile function {}{}: {}", name, version_str, e.what());
}
ret->relocation_deltas.emplace_back(delta);
prev_index = it;
}
return ret;
@@ -239,21 +312,16 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
for (const auto& item : std::filesystem::directory_iterator(directory)) {
string subdir_name = item.path().filename().string();
string subdir_path = directory.ends_with("/") ? (directory + subdir_name) : (directory + "/" + subdir_name);
if (!std::filesystem::is_directory(subdir_path)) {
function_compiler_log.warning_f("Skipping {} (not a directory)", subdir_name);
continue;
}
for (const auto& item : std::filesystem::directory_iterator(subdir_path)) {
string filename = item.path().filename().string();
auto add_file = [&](string filename) -> void {
try {
if (!filename.ends_with(".s")) {
continue;
return;
}
string name = filename.substr(0, filename.size() - 2);
if (name.ends_with(".inc")) {
continue;
return;
}
bool is_patch = name.ends_with(".patch");
@@ -299,50 +367,60 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
string path = subdir_path + "/" + filename;
string text = phosg::load_file(path);
auto code = compile_function_code(arch, subdir_path, system_dir_path, name, text);
if (code->index != 0) {
if (!this->index_to_function.emplace(code->index, code).second) {
throw runtime_error(std::format(
"duplicate function index: {:08X}", code->index));
for (auto code : compile_function_code(arch, subdir_path, system_dir_path, name, text)) {
if (code->specific_version == 0) {
code->specific_version = specific_version;
}
code->source_path = path;
code->short_name = short_name;
this->name_to_function.emplace(name, code);
if (is_patch) {
code->menu_item_id = next_menu_item_id++;
this->menu_item_id_and_specific_version_to_patch_function.emplace(
static_cast<uint64_t>(code->menu_item_id) << 32 | code->specific_version, code);
this->name_and_specific_version_to_patch_function.emplace(
std::format("{}-{:08X}", code->short_name, code->specific_version), code);
}
}
code->specific_version = specific_version;
code->source_path = path;
code->short_name = short_name;
this->name_to_function.emplace(name, code);
if (is_patch) {
code->menu_item_id = next_menu_item_id++;
this->menu_item_id_and_specific_version_to_patch_function.emplace(
static_cast<uint64_t>(code->menu_item_id) << 32 | specific_version, code);
this->name_and_specific_version_to_patch_function.emplace(
std::format("{}-{:08X}", short_name, specific_version), code);
}
string index_prefix = code->index ? std::format("{:02X} => ", code->index) : "";
string patch_prefix = is_patch ? std::format("[{:08X}/{:08X}] ", code->menu_item_id, code->specific_version) : "";
function_compiler_log.debug_f("Compiled function {}{}{} ({})",
index_prefix, patch_prefix, name, name_for_architecture(code->arch));
string patch_prefix = is_patch ? std::format("[{:08X}] ", code->menu_item_id) : "";
function_compiler_log.debug_f("Compiled function {}{} ({}; {})",
patch_prefix, name, str_for_specific_version(code->specific_version), name_for_architecture(code->arch));
}
} catch (const exception& e) {
function_compiler_log.warning_f("Failed to compile function {}: {}", filename, e.what());
}
};
if (std::filesystem::is_regular_file(subdir_path)) {
add_file(subdir_path);
} else if (std::filesystem::is_directory(subdir_path)) {
for (const auto& item : std::filesystem::directory_iterator(subdir_path)) {
string filename = item.path().filename().string();
add_file(filename);
}
} else {
function_compiler_log.warning_f("Skipping {} (unknown file type)", subdir_name);
continue;
}
}
}
shared_ptr<const Menu> FunctionCodeIndex::patch_switches_menu(
uint32_t specific_version, const std::unordered_set<std::string>& auto_patches_enabled) const {
uint32_t specific_version,
const std::unordered_set<std::string>& server_auto_patches_enabled,
const std::unordered_set<std::string>& client_auto_patches_enabled) const {
auto suffix = std::format("-{:08X}", specific_version);
auto ret = make_shared<Menu>(MenuID::PATCH_SWITCHES, "Patches");
ret->items.emplace_back(PatchesMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0);
for (const auto& it : this->name_and_specific_version_to_patch_function) {
const auto& fn = it.second;
if (fn->hide_from_patches_menu || !it.first.ends_with(suffix)) {
if (fn->hide_from_patches_menu || !it.first.ends_with(suffix) || server_auto_patches_enabled.count(fn->short_name)) {
continue;
}
string name;
name.push_back(auto_patches_enabled.count(fn->short_name) ? '*' : '-');
name.push_back(client_auto_patches_enabled.count(fn->short_name) ? '*' : '-');
name += fn->long_name.empty() ? fn->short_name : fn->long_name;
ret->items.emplace_back(fn->menu_item_id, name, fn->description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
}
+9 -12
View File
@@ -25,15 +25,15 @@ struct CompiledFunctionCode {
std::string code;
std::vector<uint16_t> relocation_deltas;
std::unordered_map<std::string, uint32_t> label_offsets;
uint32_t entrypoint_offset_offset;
uint32_t entrypoint_offset_offset = 0;
std::string source_path; // Path to source file from newserv root
std::string short_name; // Based on filename
std::string long_name; // From .meta name directive
std::string description; // From .meta description directive
uint8_t index; // 0 = unused (not registered in index_to_function)
uint32_t menu_item_id;
bool hide_from_patches_menu;
uint32_t specific_version;
uint64_t client_flag = 0; // From .meta client_flag directive
uint32_t menu_item_id = 0;
bool hide_from_patches_menu = false;
uint32_t specific_version = 0; // 0 = not a client-selectable patch
bool is_big_endian() const;
@@ -52,12 +52,6 @@ struct CompiledFunctionCode {
const char* name_for_architecture(CompiledFunctionCode::Architecture arch);
std::shared_ptr<CompiledFunctionCode> compile_function_code(
CompiledFunctionCode::Architecture arch,
const std::string& directory,
const std::string& name,
const std::string& text);
struct FunctionCodeIndex {
FunctionCodeIndex() = default;
explicit FunctionCodeIndex(const std::string& directory);
@@ -68,7 +62,10 @@ struct FunctionCodeIndex {
// Key here is e.g. "PATCHNAME-SPECIFICVERSION", with the latter in hex
std::map<std::string, std::shared_ptr<CompiledFunctionCode>> name_and_specific_version_to_patch_function;
std::shared_ptr<const Menu> patch_switches_menu(uint32_t specific_version, const std::unordered_set<std::string>& auto_patches_enabled) const;
std::shared_ptr<const Menu> patch_switches_menu(
uint32_t specific_version,
const std::unordered_set<std::string>& server_auto_patches_enabled,
const std::unordered_set<std::string>& client_auto_patches_enabled) const;
bool patch_menu_empty(uint32_t specific_version) const;
std::shared_ptr<const CompiledFunctionCode> get_patch(const std::string& name, uint32_t specific_version) const;
+3 -3
View File
@@ -193,7 +193,7 @@ std::shared_ptr<phosg::JSON> HTTPServer::generate_client_json(
{"ItemID", item.data.id.load()},
});
if (item_name_index) {
item_dict.emplace("Description", item_name_index->describe_item(item.data, false));
item_dict.emplace("Description", item_name_index->describe_item(item.data));
}
items_json.emplace_back(std::move(item_dict));
}
@@ -431,7 +431,7 @@ std::shared_ptr<phosg::JSON> HTTPServer::generate_lobby_json(
{"ItemID", item->data.id.load()},
});
if (item_name_index) {
item_dict.emplace("Description", item_name_index->describe_item(item->data, false));
item_dict.emplace("Description", item_name_index->describe_item(item->data));
}
floor_items_json.emplace_back(std::move(item_dict));
}
@@ -798,7 +798,7 @@ asio::awaitable<std::unique_ptr<HTTPResponse>> HTTPServer::handle_request(shared
} else if (req.path == "/y/data/rare-tables") {
this->require_GET(req);
ret = this->generate_rare_table_list_json();
} else if (!req.path.starts_with("/y/data/rare-tables/")) {
} else if (req.path.starts_with("/y/data/rare-tables/")) {
this->require_GET(req);
ret = co_await this->generate_rare_table_json(req.path.substr(20));
} else if (req.path == "/y/data/quests") {
+10 -11
View File
@@ -35,7 +35,7 @@ struct GVRHeader {
be_uint16_t height;
} __packed_ws__(GVRHeader, 0x10);
string encode_gvm(const phosg::Image& img, GVRDataFormat data_format, const string& internal_name, uint32_t global_index) {
string encode_gvm(const phosg::ImageRGBA8888N& img, GVRDataFormat data_format, const string& internal_name, uint32_t global_index) {
int8_t dimensions_field = -2;
{
size_t h = img.get_height();
@@ -90,17 +90,16 @@ string encode_gvm(const phosg::Image& img, GVRDataFormat data_format, const stri
for (size_t x = 0; x < img.get_width(); x += 4) {
for (size_t yy = 0; yy < 4; yy++) {
for (size_t xx = 0; xx < 4; xx++) {
uint64_t a, r, g, b;
img.read_pixel(x + xx, y + yy, &r, &g, &b, &a);
uint32_t c = img.read(x + xx, y + yy);
switch (data_format) {
case GVRDataFormat::RGB565:
w.put_u16b(encode_rgb565(r, g, b));
w.put_u16b(phosg::rgb565_for_rgba8888(c));
break;
case GVRDataFormat::RGB5A3:
w.put_u16b(encode_rgb5a3(r, g, b, a));
w.put_u16b(encode_rgb5a3(c));
break;
case GVRDataFormat::ARGB8888:
w.put_u32b(encode_argb8888(r, g, b, a));
w.put_u32b(phosg::argb8888_for_rgba8888(c));
break;
default:
throw logic_error("cannot encode pixel format");
@@ -115,15 +114,15 @@ string encode_gvm(const phosg::Image& img, GVRDataFormat data_format, const stri
static const array<uint32_t, 4> fon_colors = {0x000000FF, 0x555555FF, 0xAAAAAAFF, 0xFFFFFFFF};
phosg::Image decode_fon(const string& data, size_t width) {
phosg::ImageRGB888 decode_fon(const string& data, size_t width) {
size_t num_pixels = data.size() * 4;
size_t height = num_pixels / width;
phosg::Image ret(width, height);
phosg::ImageRGB888 ret(width, height);
phosg::BitReader r(data);
for (size_t y = 0; y < height; y++) {
for (size_t x = 0; x < width; x++) {
ret.write_pixel(x, y, fon_colors[r.read(2)]);
ret.write(x, y, fon_colors[r.read(2)]);
}
}
return ret;
@@ -133,11 +132,11 @@ constexpr size_t uabs(size_t a, size_t b) {
return (a > b) ? (a - b) : (b - a);
}
string encode_fon(const phosg::Image& img) {
string encode_fon(const phosg::ImageRGB888& img) {
phosg::BitWriter w;
for (size_t y = 0; y < img.get_height(); y++) {
for (size_t x = 0; x < img.get_width(); x++) {
uint32_t color = img.read_pixel(x, y);
uint32_t color = img.read(x, y);
size_t result_delta = 0x400;
size_t result_index = 0;
+20 -34
View File
@@ -19,43 +19,29 @@ enum class GVRDataFormat : uint8_t {
DXT1 = 0x0E,
};
std::string encode_gvm(const phosg::Image& img, GVRDataFormat data_format, const std::string& internal_name, uint32_t global_index);
phosg::Image decode_fon(const std::string& data, size_t width);
std::string encode_fon(const phosg::Image& img);
std::string encode_gvm(
const phosg::ImageRGBA8888N& img, GVRDataFormat data_format, const std::string& internal_name, uint32_t global_index);
phosg::ImageRGB888 decode_fon(const std::string& data, size_t width);
std::string encode_fon(const phosg::ImageRGB888& img);
constexpr uint16_t encode_rgb565(uint8_t r, uint8_t g, uint8_t b) {
return ((r << 8) & 0xF800) | ((g << 3) & 0x07E0) | ((b >> 3) & 0x001F);
}
constexpr uint16_t encode_rgb5a3(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
if ((a & 0xE0) == 0xE0) {
return 0x8000 | ((r << 7) & 0x7C00) | ((g << 2) & 0x03E0) | ((b >> 3) & 0x001F);
constexpr uint16_t encode_rgb5a3(uint32_t c) {
if ((phosg::get_a(c) & 0xE0) == 0xE0) {
return 0x8000 | ((phosg::get_r(c) << 7) & 0x7C00) | ((phosg::get_g(c) << 2) & 0x03E0) | ((phosg::get_b(c) >> 3) & 0x001F);
} else {
return ((a << 7) & 0x7000) | ((r << 4) & 0x0F00) | (g & 0x00F0) | ((b >> 4) & 0x000F);
return ((phosg::get_a(c) << 7) & 0x7000) | ((phosg::get_r(c) << 4) & 0x0F00) | (phosg::get_g(c) & 0x00F0) | ((phosg::get_b(c) >> 4) & 0x000F);
}
}
constexpr uint32_t encode_argb8888(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return (a << 24) | (r << 16) | (g << 8) | b;
}
constexpr uint16_t encode_argb8888_to_argb1555(uint32_t argb8888) {
// In: aaaaaaaarrrrrrrrggggggggbbbbbbbb
// Out: arrrrrgggggbbbbb
return ((argb8888 >> 9) & 0x7C00) | ((argb8888 >> 6) & 0x03E0) | ((argb8888 >> 3) & 0x001F) | ((argb8888 >> 16) & 0x8000);
}
constexpr uint16_t encode_rgba8888_to_argb1555(uint32_t rgba8888) {
// In: rrrrrrrrggggggggbbbbbbbbaaaaaaaa
// Out: arrrrrgggggbbbbb
return ((rgba8888 >> 17) & 0x7C00) | ((rgba8888 >> 14) & 0x03E0) | ((rgba8888 >> 11) & 0x001F) | ((rgba8888 << 8) & 0x8000);
}
constexpr uint32_t decode_argb1555_to_rgba8888(uint16_t argb1555) {
// In: arrrrrgggggbbbbb
// Out: rrrrrrrrggggggggbbbbbbbbaaaaaaaa
return ((argb1555 << 17) & 0xF8000000) | ((argb1555 << 12) & 0x07000000) |
((argb1555 << 14) & 0x00F80000) | ((argb1555 << 9) & 0x00070000) |
((argb1555 << 11) & 0x0000F800) | ((argb1555 << 6) & 0x00000700) |
((argb1555 & 0x8000) ? 0x000000FF : 0x00000000);
template <phosg::PixelFormat Format>
bool has_any_transparent_pixels(const phosg::Image<Format>& img) {
if constexpr (phosg::Image<Format>::HAS_ALPHA) {
for (size_t y = 0; y < img.get_height(); y++) {
for (size_t x = 0; x < img.get_height(); x++) {
if (phosg::get_a(img.read(x, y)) != 0xFF) {
return true;
}
}
}
}
return false;
}
+1 -1
View File
@@ -96,7 +96,7 @@ private:
// [0x0B] - unit modifiers
// [0x0C] - common armor DFP bonuses
// [0x0D] - common armor EVP bonuses
// [0x0E] - apparently unused
// [0x0E] - unit stars
// [0x0F] - which common weapon special to generate
// [0x10] - apparently unused
std::shared_ptr<RandomGenerator> rand_crypt;
+8 -3
View File
@@ -254,9 +254,14 @@ size_t ItemData::max_stack_size(const StackLimits& limits) const {
return limits.get(this->data1[0], this->data1[1]);
}
void ItemData::enforce_min_stack_size(const StackLimits& limits) {
if (this->stack_size(limits) == 0) {
this->data1[5] = 1;
void ItemData::enforce_stack_size_limits(const StackLimits& limits) {
if (this->data1[0] == 0x03) {
size_t max_stack_size = this->max_stack_size(limits);
if (max_stack_size > 1) {
this->data1[5] = std::clamp<uint8_t>(this->data1[5], 1, max_stack_size);
} else {
this->data1[5] = 0;
}
}
}
+2 -2
View File
@@ -118,7 +118,7 @@ struct ItemData {
// sending where needed.
// Related note: PSO V2 has an annoyingly complicated format for mags that
// doesn't match the above table. We decode this upon receipt and encode it
// imemdiately before sending when interacting with V2 clients; see the
// immediately before sending when interacting with V2 clients; see the
// implementation of decode_for_version() for details.
union {
@@ -163,7 +163,7 @@ struct ItemData {
bool is_stackable(const StackLimits& limits) const;
size_t stack_size(const StackLimits& limits) const;
size_t max_stack_size(const StackLimits& limits) const;
void enforce_min_stack_size(const StackLimits& limits);
void enforce_stack_size_limits(const StackLimits& limits);
static bool is_common_consumable(uint32_t primary_identifier);
bool is_common_consumable() const;
+86 -43
View File
@@ -97,7 +97,10 @@ const array<const char*, 0x11> name_for_s_rank_special = {
"King\'s",
};
std::string ItemNameIndex::describe_item(const ItemData& item, bool include_color_escapes, bool hide_mag_stats) const {
std::string ItemNameIndex::describe_item(const ItemData& item, uint8_t flags) const {
bool include_color_escapes = flags & ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES;
bool name_only = flags & ItemNameIndex::Flag::NAME_ONLY;
if (item.data1[0] == 0x04) {
return std::format("{}{} Meseta", include_color_escapes ? "$C7" : "", item.data2d);
}
@@ -108,13 +111,14 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
bool is_unidentified = false;
if ((item.data1[0] == 0x00) && (item.data1[4] != 0x00) && !item.is_s_rank_weapon()) {
is_unidentified = item.data1[4] & 0x80;
bool is_present = item.data1[4] & 0x40;
uint8_t special_id = item.data1[4] & 0x3F;
if (is_present) {
ret_tokens.emplace_back("Wrapped");
}
if (is_unidentified) {
ret_tokens.emplace_back("????");
if (!name_only) {
if (item.data1[4] & 0x40) {
ret_tokens.emplace_back("Wrapped");
}
if (is_unidentified) {
ret_tokens.emplace_back("????");
}
}
if (special_id) {
try {
@@ -124,7 +128,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
}
}
}
if ((item.data1[0] == 0x00) && (item.data1[2] != 0x00) && item.is_s_rank_weapon()) {
if (!name_only && (item.data1[0] == 0x00) && (item.data1[2] != 0x00) && item.is_s_rank_weapon()) {
try {
ret_tokens.emplace_back(name_for_s_rank_special.at(item.data1[2]));
} catch (const out_of_range&) {
@@ -135,9 +139,10 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
// Armors, shields, and units (0x01) can be wrapped, as can mags (0x02) and
// non-stackable tools (0x03). However, each of these item classes has its
// flags in a different location.
if (((item.data1[0] == 0x01) && (item.data1[4] & 0x40)) ||
((item.data1[0] == 0x02) && (item.data2[2] & 0x40)) ||
((item.data1[0] == 0x03) && !item.is_stackable(*this->limits) && (item.data1[3] & 0x40))) {
if (!name_only &&
(((item.data1[0] == 0x01) && (item.data1[4] & 0x40)) ||
((item.data1[0] == 0x02) && (item.data2[2] & 0x40)) ||
((item.data1[0] == 0x03) && !item.is_stackable(*this->limits) && (item.data1[3] & 0x40)))) {
ret_tokens.emplace_back("Wrapped");
}
@@ -168,7 +173,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
if (item.data1[0] == 0x00) {
// For weapons, add the grind and bonuses, or S-rank name if applicable
if (item.data1[3] > 0) {
if (!name_only && item.data1[3] > 0) {
ret_tokens.emplace_back(std::format("+{}", item.data1[3]));
}
@@ -210,18 +215,22 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
}
}
} else { // Not S-rank (extended name bits not set)
} else if (!name_only) { // Not S-rank (extended name bits not set)
size_t num_bonuses = 3;
if (item.data1[10] & 0x80) {
ret_tokens.emplace_back(std::format("K:{}", item.get_kill_count()));
num_bonuses = 2;
}
parray<int8_t, 5> bonuses(0);
for (size_t x = 0; x < 3; x++) {
for (size_t x = 0; x < num_bonuses; x++) {
uint8_t which = item.data1[6 + 2 * x];
uint8_t value = item.data1[7 + 2 * x];
if (which == 0) {
continue;
}
if (which & 0x80) {
uint16_t kill_count = ((which << 8) & 0x7F00) | (value & 0xFF);
ret_tokens.emplace_back(std::format("K:{}", kill_count));
} else if (which > 5) {
if (which > 5) {
ret_tokens.emplace_back(std::format("!PC:{:02X}{:02X}", which, value));
} else {
bonuses[which - 1] = value;
@@ -258,7 +267,11 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
ret_tokens.emplace_back(std::format("!MD:{:04X}", modifier));
}
} else { // Armor/shields
if (!name_only && (item.data1[10] & 0x80)) {
ret_tokens.emplace_back(std::format("K:{}", item.get_kill_count()));
}
} else if (!name_only) { // Armor/shields
if (item.data1[5] > 0) {
if (item.data1[5] == 1) {
ret_tokens.emplace_back("(1 slot)");
@@ -276,7 +289,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
}
}
} else if (!hide_mag_stats && (item.data1[0] == 0x02)) {
} else if (!name_only && (item.data1[0] == 0x02)) {
// For mags, add tons of info
ret_tokens.emplace_back(std::format("LV{}", item.data1[2]));
@@ -383,7 +396,7 @@ ItemData ItemNameIndex::parse_item_description(const std::string& desc) const {
}
}
}
ret.enforce_min_stack_size(*this->limits);
ret.enforce_stack_size_limits(*this->limits);
return ret;
}
@@ -522,6 +535,9 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
ret.data1w[4] = phosg::bswap16(0x8000 | (char_indexes[4] & 0x1F) | ((char_indexes[3] & 0x1F) << 5) | ((char_indexes[2] & 0x1F) << 10));
ret.data1w[5] = phosg::bswap16(0x8000 | (char_indexes[7] & 0x1F) | ((char_indexes[6] & 0x1F) << 5) | ((char_indexes[5] & 0x1F) << 10));
} else if (token.starts_with("k:")) {
ret.set_kill_count(stoul(token.substr(2), nullptr, 0));
} else {
auto p_tokens = phosg::split(token, '/');
if (p_tokens.size() > 5) {
@@ -662,7 +678,8 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
void ItemNameIndex::print_table(FILE* stream) const {
auto pmt = this->item_parameter_table;
phosg::fwrite_fmt(stream, "WEAPON => ---ID--- TYPE SKIN POINTS FLAG ATPLO ATPHI ATPRQ MSTRQ ATARQ -MST- GND PH SP ATA SB PJ 1X 1Y 2X 2Y CL A1 A2 A3 A4 A5 TB BF V1 ST* USL ---DIVISOR--- NAME\n");
phosg::fwrite_fmt(stream, "WEAPONS\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS FLAG ATPLO ATPHI ATPRQ MSTRQ ATARQ -MST- GND PH SP ATA SB(S1:AMT1,S2:AMT2) PJ 1X 1Y 2X 2Y CL A1 A2 A3 A4 A5 TB BF V1 ST* USL ---DIVISOR--- NAME\n");
for (size_t data1_1 = 0; data1_1 < pmt->num_weapon_classes; data1_1++) {
uint8_t v1_replacement = pmt->get_weapon_v1_replacement(data1_1);
float sale_divisor = pmt->get_sale_divisor(0x00, data1_1);
@@ -681,7 +698,8 @@ void ItemNameIndex::print_table(FILE* stream) const {
item.data1[2] = data1_2;
string name = this->describe_item(item);
phosg::fwrite_fmt(stream, "00{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:04X} {:5} {:5} {:5} {:5} {:5} {:5} {:3} {:02X} {:02X} {:3} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:2}* {} {} {}\n",
auto& stat_boost = pmt->get_stat_boost(w.stat_boost_entry_index);
phosg::fwrite_fmt(stream, " 00{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:04X} {:5} {:5} {:5} {:5} {:5} {:5} {:3} {:02X} {:02X} {:3} {:02X}({:02X}:{:04X},{:02X}:{:04X}) {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:2}* {} {} {}\n",
data1_1,
data1_2,
w.base.id,
@@ -699,7 +717,11 @@ void ItemNameIndex::print_table(FILE* stream) const {
w.photon,
w.special,
w.ata,
w.stat_boost,
w.stat_boost_entry_index,
stat_boost.stats[0],
stat_boost.amounts[0],
stat_boost.stats[1],
stat_boost.amounts[1],
w.projectile,
w.trail1_x,
w.trail1_y,
@@ -721,7 +743,8 @@ void ItemNameIndex::print_table(FILE* stream) const {
}
}
phosg::fwrite_fmt(stream, "ARMOR => ---ID--- TYPE SKIN POINTS -DFP- -EVP- BP BE FLAG LVL EFR ETH EIC EDK ELT DFR EVR SB TB FT A4 ST* ---DIVISOR--- NAME\n");
phosg::fwrite_fmt(stream, "ARMORS\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS -DFP- -EVP- BP BE FLAG LVL EFR ETH EIC EDK ELT DFR EVR SB(S1:AMT1,S2:AMT2) TB FT A4 ST* ---DIVISOR--- NAME\n");
for (size_t data1_1 = 1; data1_1 < 3; data1_1++) {
float sale_divisor = pmt->get_sale_divisor(0x01, data1_1);
string divisor_str = std::format("{:g}", sale_divisor);
@@ -738,7 +761,8 @@ void ItemNameIndex::print_table(FILE* stream) const {
item.data1[2] = data1_2;
string name = this->describe_item(item);
phosg::fwrite_fmt(stream, "01{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:5} {:5} {:02X} {:02X} {:04X} {:3} {:3} {:3} {:3} {:3} {:3} {:3} {:3} {:02X} {:02X} {:02X} {:02X} {:2}* {} {}\n",
auto& stat_boost = pmt->get_stat_boost(a.stat_boost_entry_index);
phosg::fwrite_fmt(stream, " 01{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:5} {:5} {:02X} {:02X} {:04X} {:3} {:3} {:3} {:3} {:3} {:3} {:3} {:3} {:02X}({:02X}:{:04X},{:02X}:{:04X}) {:02X} {:02X} {:02X} {:2}* {} {}\n",
data1_1,
data1_2,
a.base.id,
@@ -758,7 +782,11 @@ void ItemNameIndex::print_table(FILE* stream) const {
a.elt,
a.dfp_range,
a.evp_range,
a.stat_boost,
a.stat_boost_entry_index,
stat_boost.stats[0],
stat_boost.amounts[0],
stat_boost.stats[1],
stat_boost.amounts[1],
a.tech_boost,
a.flags_type,
a.unknown_a4,
@@ -768,7 +796,8 @@ void ItemNameIndex::print_table(FILE* stream) const {
}
}
phosg::fwrite_fmt(stream, "UNIT => ---ID--- TYPE SKIN POINTS STAT COUNT ST-MOD ST* ---DIVISOR--- NAME\n");
phosg::fwrite_fmt(stream, "UNITS\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS STAT COUNT ST-MOD ST* ---DIVISOR--- NAME\n");
{
float sale_divisor = pmt->get_sale_divisor(0x01, 0x03);
string divisor_str = std::format("{:g}", sale_divisor);
@@ -785,7 +814,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
item.data1[2] = data1_2;
string name = this->describe_item(item);
phosg::fwrite_fmt(stream, "0103{:02X} => {:08X} {:04X} {:04X} {:6} {:04X} {:5} {:6} {:2}* {} {}\n",
phosg::fwrite_fmt(stream, " 0103{:02X} => {:08X} {:04X} {:04X} {:6} {:04X} {:5} {:6} {:2}* {} {}\n",
data1_2,
u.base.id,
u.base.type,
@@ -800,7 +829,8 @@ void ItemNameIndex::print_table(FILE* stream) const {
}
}
phosg::fwrite_fmt(stream, "MAG => ---ID--- TYPE SKIN POINTS FTBL PB AC E1 E2 E3 E4 C1 C2 C3 C4 FLAG ---DIVISOR--- NAME\n");
phosg::fwrite_fmt(stream, "MAGS\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS FTBL PB AC E1 E2 E3 E4 C1 C2 C3 C4 FLAG ---DIVISOR--- NAME\n");
{
size_t data1_1_limit = pmt->num_mags();
for (size_t data1_1 = 0; data1_1 < data1_1_limit; data1_1++) {
@@ -816,7 +846,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
item.data1[2] = 0x00;
string name = this->describe_item(item);
phosg::fwrite_fmt(stream, "02{:02X}00 => {:08X} {:04X} {:04X} {:6} {:04X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:04X} {} {}\n",
phosg::fwrite_fmt(stream, " 02{:02X}00 => {:08X} {:04X} {:04X} {:6} {:04X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:04X} {} {}\n",
data1_1,
m.base.id,
m.base.type,
@@ -839,7 +869,8 @@ void ItemNameIndex::print_table(FILE* stream) const {
}
}
phosg::fwrite_fmt(stream, "TOOL => ---ID--- TYPE SKIN POINTS COUNT TECH -COST- ITEMFLAG ---DIVISOR--- NAME\n");
phosg::fwrite_fmt(stream, "TOOLS\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS COUNT TECH -COST- ITEMFLAG ---DIVISOR--- NAME\n");
for (size_t data1_1 = 0; data1_1 < pmt->num_tool_classes; data1_1++) {
float sale_divisor = pmt->get_sale_divisor(0x03, data1_1);
string divisor_str = std::format("{:g}", sale_divisor);
@@ -856,7 +887,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
item.set_tool_item_amount(*this->limits, 1);
string name = this->describe_item(item);
phosg::fwrite_fmt(stream, "03{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:5} {:04X} {:6} {:08X} {} {}\n",
phosg::fwrite_fmt(stream, " 03{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:5} {:04X} {:6} {:08X} {} {}\n",
data1_1,
data1_2,
t.base.id,
@@ -872,9 +903,10 @@ void ItemNameIndex::print_table(FILE* stream) const {
}
}
phosg::fwrite_fmt(stream, "CLASS => F GF RF B GB RB Z GZ RZ GR DB JL ZL SH RY RS AT RV MG\n");
phosg::fwrite_fmt(stream, "MAX TECH LEVELS\n");
phosg::fwrite_fmt(stream, " CLASS => F GF RF B GB RB Z GZ RZ GR DB JL ZL SH RY RS AT RV MG\n");
for (size_t char_class = 0; char_class < 12; char_class++) {
phosg::fwrite_fmt(stream, "{:9} =>", name_for_char_class(char_class));
phosg::fwrite_fmt(stream, " {:9} =>", name_for_char_class(char_class));
for (size_t tech_num = 0; tech_num < 0x13; tech_num++) {
uint8_t max_level = pmt->get_max_tech_level(char_class, tech_num) + 1;
if (max_level == 0x00) {
@@ -886,30 +918,40 @@ void ItemNameIndex::print_table(FILE* stream) const {
phosg::fwrite_fmt(stream, "\n");
}
phosg::fwrite_fmt(stream, "MAG FEED TABLES\n");
for (size_t table_index = 0; table_index < 8; table_index++) {
static const char* names[11] = {
"Monomate", "Dimate", "Trimate", "Monofluid",
"Difluid", "Trifluid", "Antidote", "Antiparalysis",
"Sol Atomizer", "Moon Atomizer", "Star Atomizer"};
phosg::fwrite_fmt(stream, "TABLE {:02X} => -DEF -POW -DEX MIND -IQ- SYNC\n", table_index);
phosg::fwrite_fmt(stream, " TABLE {:02X} => -DEF -POW -DEX MIND -IQ- SYNC\n", table_index);
for (size_t which = 0; which < 11; which++) {
const auto& res = pmt->get_mag_feed_result(table_index, which);
phosg::fwrite_fmt(stream, "{:14} => {:4} {:4} {:4} {:4} {:4} {:4}\n",
phosg::fwrite_fmt(stream, " {:14} => {:4} {:4} {:4} {:4} {:4} {:4}\n",
names[which], res.def, res.pow, res.dex, res.mind, res.iq, res.synchro);
}
}
phosg::fwrite_fmt(stream, "SPECIAL => TYPE COUNT ST*\n");
phosg::fwrite_fmt(stream, "SPECIAL DEFINITIONS\n");
phosg::fwrite_fmt(stream, " SPECIAL => TYPE COUNT ST* NAME\n");
for (size_t index = 0; index < pmt->num_specials; index++) {
const auto& sp = pmt->get_special(index);
uint8_t stars = pmt->get_special_stars(index);
phosg::fwrite_fmt(stream, " {:02X} => {:04X} {:5} {:2}*\n", index, sp.type, sp.amount, stars);
const char* name = "";
if (index) {
try {
name = name_for_weapon_special.at(index);
} catch (const out_of_range&) {
}
}
phosg::fwrite_fmt(stream, " {:02X} => {:04X} {:5} {:2}* {}\n", index, sp.type, sp.amount, stars, name);
}
phosg::fwrite_fmt(stream, "---USE + -EQUIP => RESULT MLV GND LVL CLS\n");
phosg::fwrite_fmt(stream, "ITEM COMBINATIONS\n");
phosg::fwrite_fmt(stream, " ---USE + -EQUIP => RESULT MLV GND LVL CLS\n");
for (const auto& combo_list_it : pmt->get_all_item_combinations()) {
for (const auto& combo : combo_list_it.second) {
phosg::fwrite_fmt(stream, "{:02X}{:02X}{:02X} + {:02X}{:02X}{:02X} => {:02X}{:02X}{:02X}",
phosg::fwrite_fmt(stream, " {:02X}{:02X}{:02X} + {:02X}{:02X}{:02X} => {:02X}{:02X}{:02X}",
combo.used_item[0], combo.used_item[1], combo.used_item[2],
combo.equipped_item[0], combo.equipped_item[1], combo.equipped_item[2],
combo.result_item[0], combo.result_item[1], combo.result_item[2]);
@@ -936,13 +978,14 @@ void ItemNameIndex::print_table(FILE* stream) const {
}
}
phosg::fwrite_fmt(stream, "EVENT ITEMS\n");
size_t num_events = pmt->num_events();
for (size_t event_number = 0; event_number < num_events; event_number++) {
phosg::fwrite_fmt(stream, "EV {:3} => PRB\n", event_number);
phosg::fwrite_fmt(stream, " EV {:3} => PRB\n", event_number);
auto events_list = pmt->get_event_items(event_number);
for (size_t z = 0; z < events_list.second; z++) {
const auto& event_item = events_list.first[z];
phosg::fwrite_fmt(stream, "{:02X}{:02X}{:02X} => {:3}\n",
phosg::fwrite_fmt(stream, " {:02X}{:02X}{:02X} => {:3}\n",
event_item.item[0], event_item.item[1], event_item.item[2], event_item.probability);
}
}
+6 -1
View File
@@ -38,7 +38,12 @@ public:
inline bool exists(const ItemData& item) const {
return this->primary_identifier_index.count(item.primary_identifier());
}
std::string describe_item(const ItemData& item, bool include_color_escapes = false, bool hide_mag_stats = false) const;
enum Flag : uint8_t {
INCLUDE_PSO_COLOR_ESCAPES = 0x01,
NAME_ONLY = 0x02,
};
std::string describe_item(const ItemData& item, uint8_t flags = 0) const;
ItemData parse_item_description(const std::string& description) const;
void print_table(FILE* stream) const;
+84 -59
View File
@@ -175,7 +175,7 @@ ItemParameterTable::WeaponV4 ItemParameterTable::WeaponV1V2::to_v4() const {
ret.photon = this->photon;
ret.special = this->special;
ret.ata = this->ata;
ret.stat_boost = this->stat_boost;
ret.stat_boost_entry_index = this->stat_boost_entry_index;
return ret;
}
@@ -195,7 +195,7 @@ ItemParameterTable::WeaponV4 ItemParameterTable::WeaponGCNTE::to_v4() const {
ret.photon = this->photon;
ret.special = this->special;
ret.ata = this->ata;
ret.stat_boost = this->stat_boost;
ret.stat_boost_entry_index = this->stat_boost_entry_index;
ret.projectile = this->projectile;
ret.trail1_x = this->trail1_x;
ret.trail1_y = this->trail1_y;
@@ -225,7 +225,7 @@ ItemParameterTable::WeaponV4 ItemParameterTable::WeaponV3T<BE>::to_v4() const {
ret.photon = this->photon;
ret.special = this->special;
ret.ata = this->ata;
ret.stat_boost = this->stat_boost;
ret.stat_boost_entry_index = this->stat_boost_entry_index;
ret.projectile = this->projectile;
ret.trail1_x = this->trail1_x;
ret.trail1_y = this->trail1_y;
@@ -277,7 +277,7 @@ ItemParameterTable::ArmorOrShieldV4 ItemParameterTable::ArmorOrShieldV1V2::to_v4
ret.elt = this->elt;
ret.dfp_range = this->dfp_range;
ret.evp_range = this->evp_range;
ret.stat_boost = this->stat_boost;
ret.stat_boost_entry_index = this->stat_boost_entry_index;
ret.tech_boost = this->tech_boost;
ret.flags_type = this->flags_type;
ret.unknown_a4 = this->unknown_a4;
@@ -303,7 +303,7 @@ ItemParameterTable::ArmorOrShieldV4 ItemParameterTable::ArmorOrShieldV3T<BE>::to
ret.elt = this->elt;
ret.dfp_range = this->dfp_range;
ret.evp_range = this->evp_range;
ret.stat_boost = this->stat_boost;
ret.stat_boost_entry_index = this->stat_boost_entry_index;
ret.tech_boost = this->tech_boost;
ret.flags_type = this->flags_type;
ret.unknown_a4 = this->unknown_a4;
@@ -522,25 +522,22 @@ const ItemParameterTable::ArmorOrShieldV4& ItemParameterTable::get_armor_or_shie
}
return ret;
} catch (const std::out_of_range&) {
ArmorOrShieldV4 def_v4;
if (this->offsets_dc_protos) {
def_v4 = indirect_lookup_2d<ArmorOrShieldDCProtos, false>(this->r, this->offsets_dc_protos->armor_table, data1_1 - 1, data1_2).to_v4();
} else if (this->offsets_v1_v2) {
def_v4 = indirect_lookup_2d<ArmorOrShieldV1V2, false>(this->r, this->offsets_v1_v2->armor_table, data1_1 - 1, data1_2).to_v4();
} else if (this->offsets_gc_nte) {
def_v4 = indirect_lookup_2d<ArmorOrShieldV3BE, true>(this->r, this->offsets_gc_nte->armor_table, data1_1 - 1, data1_2).to_v4();
} else if (this->offsets_v3_le) {
def_v4 = indirect_lookup_2d<ArmorOrShieldV3, false>(this->r, this->offsets_v3_le->armor_table, data1_1 - 1, data1_2).to_v4();
} else if (this->offsets_v3_be) {
def_v4 = indirect_lookup_2d<ArmorOrShieldV3BE, true>(this->r, this->offsets_v3_be->armor_table, data1_1 - 1, data1_2).to_v4();
} else {
throw logic_error("table is not v2, v3, or v4");
while (data1_2 >= parsed_vec.size()) {
auto& def_v4 = parsed_vec.emplace_back();
if (this->offsets_dc_protos) {
def_v4 = indirect_lookup_2d<ArmorOrShieldDCProtos, false>(this->r, this->offsets_dc_protos->armor_table, data1_1 - 1, parsed_vec.size() - 1).to_v4();
} else if (this->offsets_v1_v2) {
def_v4 = indirect_lookup_2d<ArmorOrShieldV1V2, false>(this->r, this->offsets_v1_v2->armor_table, data1_1 - 1, parsed_vec.size() - 1).to_v4();
} else if (this->offsets_gc_nte) {
def_v4 = indirect_lookup_2d<ArmorOrShieldV3BE, true>(this->r, this->offsets_gc_nte->armor_table, data1_1 - 1, parsed_vec.size() - 1).to_v4();
} else if (this->offsets_v3_le) {
def_v4 = indirect_lookup_2d<ArmorOrShieldV3, false>(this->r, this->offsets_v3_le->armor_table, data1_1 - 1, parsed_vec.size() - 1).to_v4();
} else if (this->offsets_v3_be) {
def_v4 = indirect_lookup_2d<ArmorOrShieldV3BE, true>(this->r, this->offsets_v3_be->armor_table, data1_1 - 1, parsed_vec.size() - 1).to_v4();
} else {
throw logic_error("table is not v2, v3, or v4");
}
}
if (data1_2 >= parsed_vec.size()) {
parsed_vec.resize(data1_2 + 1);
}
parsed_vec[data1_2] = def_v4;
return parsed_vec[data1_2];
}
}
@@ -575,24 +572,22 @@ const ItemParameterTable::UnitV4& ItemParameterTable::get_unit(uint8_t data1_2)
}
return ret;
} catch (const std::out_of_range&) {
UnitV4 def_v4;
if (this->offsets_dc_protos) {
def_v4 = indirect_lookup_2d<UnitDCProtos, false>(this->r, this->offsets_dc_protos->unit_table, 0, data1_2).to_v4();
} else if (this->offsets_v1_v2) {
def_v4 = indirect_lookup_2d<UnitV1V2, false>(this->r, this->offsets_v1_v2->unit_table, 0, data1_2).to_v4();
} else if (this->offsets_gc_nte) {
def_v4 = indirect_lookup_2d<UnitV3BE, true>(this->r, this->offsets_gc_nte->unit_table, 0, data1_2).to_v4();
} else if (this->offsets_v3_le) {
def_v4 = indirect_lookup_2d<UnitV3, false>(this->r, this->offsets_v3_le->unit_table, 0, data1_2).to_v4();
} else if (this->offsets_v3_be) {
def_v4 = indirect_lookup_2d<UnitV3BE, true>(this->r, this->offsets_v3_be->unit_table, 0, data1_2).to_v4();
} else {
throw logic_error("table is not v2, v3, or v4");
while (data1_2 >= this->parsed_units.size()) {
auto& def_v4 = this->parsed_units.emplace_back();
if (this->offsets_dc_protos) {
def_v4 = indirect_lookup_2d<UnitDCProtos, false>(this->r, this->offsets_dc_protos->unit_table, 0, this->parsed_units.size() - 1).to_v4();
} else if (this->offsets_v1_v2) {
def_v4 = indirect_lookup_2d<UnitV1V2, false>(this->r, this->offsets_v1_v2->unit_table, 0, this->parsed_units.size() - 1).to_v4();
} else if (this->offsets_gc_nte) {
def_v4 = indirect_lookup_2d<UnitV3BE, true>(this->r, this->offsets_gc_nte->unit_table, 0, this->parsed_units.size() - 1).to_v4();
} else if (this->offsets_v3_le) {
def_v4 = indirect_lookup_2d<UnitV3, false>(this->r, this->offsets_v3_le->unit_table, 0, this->parsed_units.size() - 1).to_v4();
} else if (this->offsets_v3_be) {
def_v4 = indirect_lookup_2d<UnitV3BE, true>(this->r, this->offsets_v3_be->unit_table, 0, this->parsed_units.size() - 1).to_v4();
} else {
throw logic_error("table is not v2, v3, or v4");
}
}
if (data1_2 >= this->parsed_units.size()) {
this->parsed_units.resize(data1_2 + 1);
}
this->parsed_units[data1_2] = def_v4;
return this->parsed_units[data1_2];
}
}
@@ -627,28 +622,26 @@ const ItemParameterTable::MagV4& ItemParameterTable::get_mag(uint8_t data1_1) co
}
return ret;
} catch (const std::out_of_range&) {
MagV4 def_v4;
if (this->offsets_dc_protos) {
def_v4 = indirect_lookup_2d<MagV1, false>(this->r, this->offsets_dc_protos->mag_table, 0, data1_1).to_v4();
} else if (this->offsets_v1_v2) {
if (is_v1(this->version)) {
def_v4 = indirect_lookup_2d<MagV1, false>(this->r, this->offsets_v1_v2->mag_table, 0, data1_1).to_v4();
while (data1_1 >= this->parsed_mags.size()) {
auto& def_v4 = this->parsed_mags.emplace_back();
if (this->offsets_dc_protos) {
def_v4 = indirect_lookup_2d<MagV1, false>(this->r, this->offsets_dc_protos->mag_table, 0, this->parsed_mags.size() - 1).to_v4();
} else if (this->offsets_v1_v2) {
if (is_v1(this->version)) {
def_v4 = indirect_lookup_2d<MagV1, false>(this->r, this->offsets_v1_v2->mag_table, 0, this->parsed_mags.size() - 1).to_v4();
} else {
def_v4 = indirect_lookup_2d<MagV2, false>(this->r, this->offsets_v1_v2->mag_table, 0, this->parsed_mags.size() - 1).to_v4();
}
} else if (this->offsets_gc_nte) {
def_v4 = indirect_lookup_2d<MagV3BE, true>(this->r, this->offsets_gc_nte->mag_table, 0, this->parsed_mags.size() - 1).to_v4();
} else if (this->offsets_v3_le) {
def_v4 = indirect_lookup_2d<MagV3, false>(this->r, this->offsets_v3_le->mag_table, 0, this->parsed_mags.size() - 1).to_v4();
} else if (this->offsets_v3_be) {
def_v4 = indirect_lookup_2d<MagV3BE, true>(this->r, this->offsets_v3_be->mag_table, 0, this->parsed_mags.size() - 1).to_v4();
} else {
def_v4 = indirect_lookup_2d<MagV2, false>(this->r, this->offsets_v1_v2->mag_table, 0, data1_1).to_v4();
throw logic_error("table is not v2, v3, or v4");
}
} else if (this->offsets_gc_nte) {
def_v4 = indirect_lookup_2d<MagV3BE, true>(this->r, this->offsets_gc_nte->mag_table, 0, data1_1).to_v4();
} else if (this->offsets_v3_le) {
def_v4 = indirect_lookup_2d<MagV3, false>(this->r, this->offsets_v3_le->mag_table, 0, data1_1).to_v4();
} else if (this->offsets_v3_be) {
def_v4 = indirect_lookup_2d<MagV3BE, true>(this->r, this->offsets_v3_be->mag_table, 0, data1_1).to_v4();
} else {
throw logic_error("table is not v2, v3, or v4");
}
if (data1_1 >= this->parsed_mags.size()) {
this->parsed_mags.resize(data1_1 + 1);
}
this->parsed_mags[data1_1] = def_v4;
return this->parsed_mags[data1_1];
}
}
@@ -928,6 +921,38 @@ const ItemParameterTable::Special& ItemParameterTable::get_special(uint8_t speci
}
}
const ItemParameterTable::StatBoost& ItemParameterTable::get_stat_boost(uint8_t entry_index) const {
if (this->offsets_dc_protos) {
return this->r.pget<StatBoost>(this->offsets_dc_protos->stat_boost_table + sizeof(StatBoost) * entry_index);
} else if (this->offsets_v1_v2) {
return this->r.pget<StatBoost>(this->offsets_v1_v2->stat_boost_table + sizeof(StatBoost) * entry_index);
} else if (this->offsets_v3_le) {
return this->r.pget<StatBoost>(this->offsets_v3_le->stat_boost_table + sizeof(StatBoost) * entry_index);
} else if (this->offsets_gc_nte) {
while (entry_index >= this->parsed_stat_boosts.size()) {
const auto& sb_be = this->r.pget<StatBoostBE>(this->offsets_gc_nte->stat_boost_table + sizeof(StatBoostBE) * this->parsed_stat_boosts.size());
auto& sb = this->parsed_stat_boosts.emplace_back();
sb.stats = sb_be.stats;
sb.amounts[0] = sb_be.amounts[0];
sb.amounts[1] = sb_be.amounts[1];
}
return this->parsed_stat_boosts[entry_index];
} else if (this->offsets_v3_be) {
while (entry_index >= this->parsed_stat_boosts.size()) {
const auto& sb_be = this->r.pget<StatBoostBE>(this->offsets_v3_be->stat_boost_table + sizeof(StatBoostBE) * this->parsed_stat_boosts.size());
auto& sb = this->parsed_stat_boosts.emplace_back();
sb.stats = sb_be.stats;
sb.amounts[0] = sb_be.amounts[0];
sb.amounts[1] = sb_be.amounts[1];
}
return this->parsed_stat_boosts[entry_index];
} else if (this->offsets_v4) {
return this->r.pget<StatBoost>(this->offsets_v4->stat_boost_table + sizeof(StatBoost) * entry_index);
} else {
throw logic_error("table is not v2, v3, or v4");
}
}
uint8_t ItemParameterTable::get_max_tech_level(uint8_t char_class, uint8_t tech_num) const {
if (char_class >= 12) {
throw out_of_range("invalid character class");
+31 -9
View File
@@ -71,7 +71,7 @@ public:
/* 11 */ uint8_t photon = 0;
/* 12 */ uint8_t special = 0;
/* 13 */ uint8_t ata = 0;
/* 14 */ uint8_t stat_boost = 0; // TODO: This could be larger (16 or 32 bits)
/* 14 */ uint8_t stat_boost_entry_index = 0; // TODO: This could be larger (16 or 32 bits)
/* 15 */ parray<uint8_t, 3> unknown_a9;
/* 18 */
@@ -91,7 +91,7 @@ public:
/* 17 */ uint8_t photon = 0;
/* 18 */ uint8_t special = 0;
/* 19 */ uint8_t ata = 0;
/* 1A */ uint8_t stat_boost = 0;
/* 1A */ uint8_t stat_boost_entry_index = 0;
/* 1B */ uint8_t projectile = 0;
/* 1C */ int8_t trail1_x = 0;
/* 1D */ int8_t trail1_y = 0;
@@ -120,7 +120,7 @@ public:
/* 17 */ uint8_t photon = 0;
/* 18 */ uint8_t special = 0;
/* 19 */ uint8_t ata = 0;
/* 1A */ uint8_t stat_boost = 0;
/* 1A */ uint8_t stat_boost_entry_index = 0;
/* 1B */ uint8_t projectile = 0;
/* 1C */ int8_t trail1_x = 0;
/* 1D */ int8_t trail1_y = 0;
@@ -162,7 +162,7 @@ public:
/* 1B */ uint8_t photon = 0;
/* 1C */ uint8_t special = 0;
/* 1D */ uint8_t ata = 0;
/* 1E */ uint8_t stat_boost = 0;
/* 1E */ uint8_t stat_boost_entry_index = 0;
/* 1F */ uint8_t projectile = 0;
/* 20 */ int8_t trail1_x = 0;
/* 21 */ int8_t trail1_y = 0;
@@ -201,7 +201,7 @@ public:
template <typename BaseT, bool BE>
struct ArmorOrShieldFinalT : ArmorOrShieldT<BaseT, BE> {
/* 14 */ uint8_t stat_boost = 0;
/* 14 */ uint8_t stat_boost_entry_index = 0;
/* 15 */ uint8_t tech_boost = 0;
// TODO: Figure out what this does. Only a few values appear to do anything:
// Shields:
@@ -391,10 +391,30 @@ public:
template <bool BE>
struct StatBoostT {
uint8_t stat1 = 0;
uint8_t stat2 = 0;
U16T<BE> amount1 = 0;
U16T<BE> amount2 = 0;
// Only the first of these stat/amount pairs is used in most versions of
// the game. In DC 11/2000 Sega apparently changed the loop from
// `for (z = 0; z != 2; z++)` to `for (z = 0; z != 1; z++)`, so only the
// first stat/amount pair is used on all versions after DC NTE.
// Values for stats:
// 01 = ATP bonus
// 02 = ATA bonus
// 03 = EVP bonus
// 04 = DFP bonus
// 05 = MST bonus
// 06 = HP bonus
// 07 = LCK bonus
// 08 = all of the above bonuses except HP
// 09 = ATP penalty
// 0A = ATA penalty
// 0B = EVP penalty
// 0C = DFP penalty
// 0D = MST penalty
// 0E = HP penalty
// 0F = LCK penalty
// 10 = all of the above penalties except HP
// Anything else (including 00) = no bonus or penalty
parray<uint8_t, 2> stats = 0;
parray<U16T<BE>, 2> amounts;
} __attribute__((packed));
using StatBoost = StatBoostT<false>;
using StatBoostBE = StatBoostT<true>;
@@ -476,6 +496,7 @@ public:
uint8_t get_item_stars(uint32_t id) const;
uint8_t get_special_stars(uint8_t special) const;
const Special& get_special(uint8_t special) const;
const StatBoost& get_stat_boost(uint8_t entry_index) const;
uint8_t get_max_tech_level(uint8_t char_class, uint8_t tech_num) const;
uint8_t get_weapon_v1_replacement(uint8_t data1_1) const;
@@ -624,6 +645,7 @@ protected:
mutable std::vector<MagV4> parsed_mags;
mutable std::unordered_map<uint16_t, ToolV4> parsed_tools;
mutable std::vector<Special> parsed_specials;
mutable std::vector<StatBoost> parsed_stat_boosts;
// Key is used_item. We can't index on (used_item, equipped_item) because
// equipped_item may contain wildcards, and the matching order matters.
+9
View File
@@ -296,6 +296,15 @@ uint16_t Lobby::quest_version_flags() const {
return ret;
}
uint8_t Lobby::client_extension_flags() const {
for (auto lc : this->clients) {
if (lc && !lc->check_flag(Client::Flag::HAS_ENEMY_DAMAGE_SYNC_PATCH)) {
return 0x01;
}
}
return 0x81;
}
void Lobby::load_maps() {
auto rare_rates = this->rare_enemy_rates ? this->rare_enemy_rates : MapState::DEFAULT_RARE_ENEMIES;
+1
View File
@@ -213,6 +213,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
void create_item_creator(Version logic_version = Version::UNKNOWN);
uint8_t effective_section_id() const;
uint16_t quest_version_flags() const;
uint8_t client_extension_flags() const;
void load_maps();
void create_ep3_server();
+17
View File
@@ -28,6 +28,23 @@ static void set_log_level_from_json(
}
}
void set_all_log_levels(phosg::LogLevel level) {
channel_exceptions_log.min_level = level;
client_log.min_level = level;
command_data_log.min_level = level;
config_log.min_level = level;
dns_server_log.min_level = level;
function_compiler_log.min_level = level;
ip_stack_simulator_log.min_level = level;
lobby_log.min_level = level;
patch_index_log.min_level = level;
player_data_log.min_level = level;
proxy_server_log.min_level = level;
replay_log.min_level = level;
server_log.min_level = level;
static_game_data_log.min_level = level;
}
void set_log_levels_from_json(const phosg::JSON& json) {
set_log_level_from_json(channel_exceptions_log, json, "ChannelExceptions");
set_log_level_from_json(client_log, json, "Clients");
+1
View File
@@ -18,4 +18,5 @@ extern phosg::PrefixedLogger replay_log;
extern phosg::PrefixedLogger server_log;
extern phosg::PrefixedLogger static_game_data_log;
void set_all_log_levels(phosg::LogLevel level);
void set_log_levels_from_json(const phosg::JSON& json);
+211 -122
View File
@@ -663,6 +663,19 @@ Action a_generate_pc_v2_registry(
write_output_data(args, output_data.data(), output_data.size(), "reg");
});
Action a_encrypt_challenge_time(
"encrypt-challenge-time", nullptr, +[](phosg::Arguments& args) {
uint16_t time = args.get<uint16_t>(1);
uint32_t ret = encrypt_challenge_time(time);
phosg::fwrite_fmt(stderr, "{} => {:08X}\n", phosg::format_duration(time * 1000000), ret);
});
Action a_decrypt_challenge_time(
"decrypt-challenge-time", nullptr, +[](phosg::Arguments& args) {
uint32_t time = args.get<uint32_t>(1, phosg::Arguments::IntFormat::HEX);
uint16_t ret = decrypt_challenge_time(time);
phosg::fwrite_fmt(stderr, "{:08X} => {}\n", time, phosg::format_duration(ret * 1000000));
});
Action a_encrypt_challenge_data(
"encrypt-challenge-data", nullptr, +[](phosg::Arguments& args) {
string data = read_input_data(args);
@@ -846,85 +859,6 @@ Action a_encrypt_vms_save("encrypt-vms-save", "\
hexadecimal value.\n",
a_encrypt_decrypt_vms_save_fn);
static void a_encrypt_decrypt_gci_save_fn(phosg::Arguments& args) {
bool is_decrypt = (args.get<string>(0) == "decrypt-gci-save");
bool skip_checksum = args.get<bool>("skip-checksum");
string seed = args.get<string>("seed");
string system_filename = args.get<string>("sys");
int64_t override_round2_seed = args.get<int64_t>("round2-seed", -1, phosg::Arguments::IntFormat::HEX);
uint32_t round1_seed;
if (!system_filename.empty()) {
string system_data = phosg::load_file(system_filename);
phosg::StringReader r(system_data);
const auto& header = r.get<PSOGCIFileHeader>();
header.check();
const auto& system = r.get<PSOGCSystemFile>();
round1_seed = system.creation_timestamp;
} else if (!seed.empty()) {
round1_seed = stoul(seed, nullptr, 16);
} else {
throw runtime_error("either --sys or --seed must be given");
}
auto data = read_input_data(args);
phosg::StringReader r(data);
const auto& header = r.get<PSOGCIFileHeader>();
header.check();
size_t data_start_offset = r.where();
auto process_file = [&]<typename StructT>() {
if (is_decrypt) {
const void* data_section = r.getv(header.data_size);
auto decrypted = decrypt_fixed_size_data_section_t<StructT, true>(
data_section, header.data_size, round1_seed, skip_checksum, override_round2_seed);
*reinterpret_cast<StructT*>(data.data() + data_start_offset) = decrypted;
} else {
const auto& s = r.get<StructT>();
auto encrypted = encrypt_fixed_size_data_section_t<StructT, true>(s, round1_seed);
if (data_start_offset + encrypted.size() > data.size()) {
throw runtime_error("encrypted result exceeds file size");
}
memcpy(data.data() + data_start_offset, encrypted.data(), encrypted.size());
}
};
if (header.data_size == sizeof(PSOGCGuildCardFile)) {
process_file.template operator()<PSOGCGuildCardFile>();
} else if (header.is_ep12() && (header.data_size == sizeof(PSOGCCharacterFile))) {
process_file.template operator()<PSOGCCharacterFile>();
} else if (header.is_ep3() && (header.data_size == sizeof(PSOGCEp3CharacterFile))) {
auto* charfile = reinterpret_cast<PSOGCEp3CharacterFile*>(data.data() + data_start_offset);
if (!is_decrypt) {
for (size_t z = 0; z < charfile->characters.size(); z++) {
charfile->characters[z].ep3_config.encrypt(phosg::random_object<uint8_t>());
}
}
process_file.template operator()<PSOGCEp3CharacterFile>();
if (is_decrypt) {
for (size_t z = 0; z < charfile->characters.size(); z++) {
charfile->characters[z].ep3_config.decrypt();
}
}
} else {
throw runtime_error("unrecognized save type");
}
write_output_data(args, data.data(), data.size(), is_decrypt ? "gcid" : "gci");
}
Action a_decrypt_gci_save("decrypt-gci-save", nullptr, a_encrypt_decrypt_gci_save_fn);
Action a_encrypt_gci_save("encrypt-gci-save", "\
encrypt-gci-save CRYPT-OPTION INPUT-FILENAME [OUTPUT-FILENAME]\n\
decrypt-gci-save CRYPT-OPTION INPUT-FILENAME [OUTPUT-FILENAME]\n\
Encrypt or decrypt a character or Guild Card file in GCI format. If\n\
encrypting, the checksum is also recomputed and stored in the encrypted\n\
file. CRYPT-OPTION is required; it can be either --sys=SYSTEM-FILENAME\n\
(specifying the name of the corresponding PSO_SYSTEM .gci file) or\n\
--seed=ROUND1-SEED (specified as a 32-bit hexadecimal number).\n",
a_encrypt_decrypt_gci_save_fn);
static void a_encrypt_decrypt_pc_save_fn(phosg::Arguments& args) {
bool is_decrypt = (args.get<string>(0) == "decrypt-pc-save");
bool skip_checksum = args.get<bool>("skip-checksum");
@@ -1021,6 +955,137 @@ static void a_encrypt_decrypt_save_data_fn(phosg::Arguments& args) {
write_output_data(args, output_data.data(), output_data.size(), "dec");
}
static void a_encrypt_decrypt_gci_save_fn(phosg::Arguments& args) {
bool is_decrypt = (args.get<string>(0) == "decrypt-gci-save");
bool skip_checksum = args.get<bool>("skip-checksum");
string seed = args.get<string>("seed");
string system_filename = args.get<string>("sys");
int64_t override_round2_seed = args.get<int64_t>("round2-seed", -1, phosg::Arguments::IntFormat::HEX);
uint32_t round1_seed;
if (!system_filename.empty()) {
string system_data = phosg::load_file(system_filename);
phosg::StringReader r(system_data);
const auto& header = r.get<PSOGCIFileHeader>();
header.check();
const auto& system = r.get<PSOGCSystemFile>();
round1_seed = system.creation_timestamp;
} else if (!seed.empty()) {
round1_seed = stoul(seed, nullptr, 16);
} else {
throw runtime_error("either --sys or --seed must be given");
}
auto data = read_input_data(args);
phosg::StringReader r(data);
const auto& header = r.get<PSOGCIFileHeader>();
header.check();
size_t data_start_offset = r.where();
auto process_file = [&]<typename StructT>() {
if (is_decrypt) {
const void* data_section = r.getv(header.data_size);
auto decrypted = decrypt_fixed_size_data_section_t<StructT, true>(
data_section, header.data_size, round1_seed, skip_checksum, override_round2_seed);
*reinterpret_cast<StructT*>(data.data() + data_start_offset) = decrypted;
} else {
const auto& s = r.get<StructT>();
auto encrypted = encrypt_fixed_size_data_section_t<StructT, true>(s, round1_seed);
if (data_start_offset + encrypted.size() > data.size()) {
throw runtime_error("encrypted result exceeds file size");
}
memcpy(data.data() + data_start_offset, encrypted.data(), encrypted.size());
}
};
if (header.data_size == sizeof(PSOGCGuildCardFile)) {
process_file.template operator()<PSOGCGuildCardFile>();
} else if (header.is_ep12() && (header.data_size == sizeof(PSOGCCharacterFile))) {
process_file.template operator()<PSOGCCharacterFile>();
} else if (header.is_ep3() && (header.data_size == sizeof(PSOGCEp3CharacterFile))) {
auto* charfile = reinterpret_cast<PSOGCEp3CharacterFile*>(data.data() + data_start_offset);
if (!is_decrypt) {
for (size_t z = 0; z < charfile->characters.size(); z++) {
charfile->characters[z].ep3_config.encrypt(phosg::random_object<uint8_t>());
}
}
process_file.template operator()<PSOGCEp3CharacterFile>();
if (is_decrypt) {
for (size_t z = 0; z < charfile->characters.size(); z++) {
charfile->characters[z].ep3_config.decrypt();
}
}
} else {
throw runtime_error("unrecognized save type");
}
write_output_data(args, data.data(), data.size(), is_decrypt ? "gcid" : "gci");
}
Action a_decrypt_gci_save("decrypt-gci-save", nullptr, a_encrypt_decrypt_gci_save_fn);
Action a_encrypt_gci_save("encrypt-gci-save", "\
encrypt-gci-save CRYPT-OPTION INPUT-FILENAME [OUTPUT-FILENAME]\n\
decrypt-gci-save CRYPT-OPTION INPUT-FILENAME [OUTPUT-FILENAME]\n\
Encrypt or decrypt a character or Guild Card file in GCI format. If\n\
encrypting, the checksum is also recomputed and stored in the encrypted\n\
file. CRYPT-OPTION is required; it can be either --sys=SYSTEM-FILENAME\n\
(specifying the name of the corresponding PSO_SYSTEM .gci file) or\n\
--seed=ROUND1-SEED (specified as a 32-bit hexadecimal number).\n",
a_encrypt_decrypt_gci_save_fn);
Action a_decrypt_xbox_save(
"decrypt-xbox-save", "\
decrypt-xbox-save CRYPT-OPTION INPUT-FILENAME [OUTPUT-FILENAME]\n\
Decrypt a character or Guild Card file in Xbox format. CRYPT-OPTION is\n\
required; it can be either --sys=SYSTEM-FILENAME (specifying the name of\n\
the corresponding PSO_SYSTEM file) or --seed=ROUND1-SEED (specified as a\n\
32-bit hexadecimal number).\n",
+[](phosg::Arguments& args) {
bool skip_checksum = args.get<bool>("skip-checksum");
string seed = args.get<string>("seed");
string system_filename = args.get<string>("sys");
int64_t override_round2_seed = args.get<int64_t>("round2-seed", -1, phosg::Arguments::IntFormat::HEX);
uint32_t round1_seed;
if (!system_filename.empty()) {
string system_data = phosg::load_file(system_filename);
phosg::StringReader r(system_data);
const auto& header = r.get<PSOXBFileHeader>();
header.check();
const auto& system = r.get<PSOXBSystemFile>();
round1_seed = system.creation_timestamp;
} else if (!seed.empty()) {
round1_seed = stoul(seed, nullptr, 16);
} else {
throw runtime_error("either --sys or --seed must be given");
}
auto data = read_input_data(args);
phosg::StringReader r(data);
const auto& header = r.get<PSOXBFileHeader>();
header.check();
size_t data_start_offset = r.where();
auto process_file = [&]<typename StructT>() {
const void* data_section = r.getv(header.data_size);
auto decrypted = decrypt_fixed_size_data_section_t<StructT, false>(
data_section, header.data_size, round1_seed, skip_checksum, override_round2_seed);
*reinterpret_cast<StructT*>(data.data() + data_start_offset) = decrypted;
};
if (header.data_size == sizeof(PSOXBGuildCardFile)) {
process_file.template operator()<PSOXBGuildCardFile>();
} else if (header.data_size == sizeof(PSOXBCharacterFile)) {
process_file.template operator()<PSOXBCharacterFile>();
} else {
throw runtime_error("unrecognized save type");
}
write_output_data(args, data.data(), data.size(), "dec");
});
// TODO: Write usage text for these actions
Action a_decrypt_save_data("decrypt-save-data", nullptr, a_encrypt_decrypt_save_data_fn);
Action a_encrypt_save_data("encrypt-save-data", nullptr, a_encrypt_decrypt_save_data_fn);
@@ -1101,7 +1166,7 @@ Action a_decode_gci_snapshot(
}
auto img = file.decode_image();
string saved = img.save(phosg::Image::Format::WINDOWS_BITMAP);
string saved = img.serialize(phosg::ImageFormat::WINDOWS_BITMAP);
write_output_data(args, saved.data(), saved.size(), "bmp");
});
@@ -1112,13 +1177,16 @@ Action a_encode_gvm(
GVM file can be used as an Episode 3 lobby banner.\n",
+[](phosg::Arguments& args) {
const string& input_filename = args.get<string>(1, false);
phosg::Image img;
string data;
if (!input_filename.empty() && (input_filename != "-")) {
img = phosg::Image(input_filename);
data = phosg::load_file(input_filename);
} else {
img = phosg::Image(stdin);
data = phosg::read_all(stdin);
}
string encoded = encode_gvm(img, img.get_has_alpha() ? GVRDataFormat::RGB5A3 : GVRDataFormat::RGB565, "image.gvr", 0);
auto img = phosg::ImageRGBA8888N::from_file_data(data);
// If the image has any transparent pixels at all, use RGB5A3
string encoded = encode_gvm(
img, has_any_transparent_pixels(img) ? GVRDataFormat::RGB5A3 : GVRDataFormat::RGB565, "image.gvr", 0);
write_output_data(args, encoded.data(), encoded.size(), "gvm");
});
@@ -1131,7 +1199,7 @@ Action a_decode_bitmap_font(
+[](phosg::Arguments& args) {
std::string data = read_input_data(args);
size_t width = args.get<size_t>("width");
std::string bmp_data = decode_fon(data, width).save(phosg::Image::Format::WINDOWS_BITMAP);
std::string bmp_data = decode_fon(data, width).serialize(phosg::ImageFormat::WINDOWS_BITMAP);
write_output_data(args, bmp_data.data(), bmp_data.size(), "bmp");
});
Action a_encode_bitmap_font(
@@ -1142,12 +1210,13 @@ Action a_encode_bitmap_font(
original fon\'s dimensions.\n",
+[](phosg::Arguments& args) {
const string& input_filename = args.get<string>(1, false);
phosg::Image img;
string data;
if (!input_filename.empty() && (input_filename != "-")) {
img = phosg::Image(input_filename);
data = phosg::load_file(input_filename);
} else {
img = phosg::Image(stdin);
data = phosg::read_all(stdin);
}
auto img = phosg::ImageRGB888::from_file_data(data);
string encoded = encode_fon(img);
write_output_data(args, encoded.data(), encoded.size(), "fon");
});
@@ -1647,9 +1716,10 @@ Action a_assemble_all_patches(
phosg::StringWriter w;
string data = prepare_send_function_call_data(
code, {}, nullptr, 0, checksum_addr, checksum_size, override_start_addr, encrypted);
w.put(PSOCommandHeaderDCV3{.command = 0xB2, .flag = code->index, .size = data.size() + 4});
w.put(PSOCommandHeaderDCV3{.command = 0xB2, .flag = 0x00, .size = data.size() + 4});
w.write(data);
string out_path = code->source_path + (encrypted ? ".enc.bin" : ".std.bin");
string out_path = std::format("{}.{}.{}.bin",
code->source_path, str_for_specific_version(code->specific_version), (encrypted ? "enc" : "std"));
phosg::save_file(out_path, w.str());
phosg::fwrite_fmt(stderr, "... {}\n", out_path);
}
@@ -2082,6 +2152,20 @@ Action a_convert_rare_item_set(
throw runtime_error("cannot determine output format; use a filename ending with .json, .gsl, .gslb, or .afs");
}
});
static shared_ptr<CommonItemSet> load_common_item_set(const std::string& filename, bool big_endian) {
auto data = make_shared<string>(phosg::load_file(filename));
if (filename.ends_with(".json")) {
return make_shared<JSONCommonItemSet>(phosg::JSON::parse(*data));
} else if (filename.ends_with(".gsl")) {
return make_shared<GSLV3V4CommonItemSet>(data, big_endian);
} else if (filename.ends_with(".gslb")) {
return make_shared<GSLV3V4CommonItemSet>(data, true);
} else {
throw runtime_error("cannot determine input format; use a filename ending with .json, .gsl, or .gslb");
}
}
Action a_convert_common_item_set(
"convert-common-item-set", "\
convert-common-item-set INPUT-FILENAME [OUTPUT-FILENAME]\n\
@@ -2097,27 +2181,32 @@ Action a_convert_common_item_set(
throw runtime_error("input filename must be given");
}
auto data = make_shared<string>(read_input_data(args));
shared_ptr<CommonItemSet> cs;
if (input_filename.ends_with(".json")) {
cs = make_shared<JSONCommonItemSet>(phosg::JSON::parse(*data));
} else if (input_filename.ends_with(".gsl")) {
cs = make_shared<GSLV3V4CommonItemSet>(data, args.get<bool>("big-endian"));
} else if (input_filename.ends_with(".gslb")) {
cs = make_shared<GSLV3V4CommonItemSet>(data, true);
} else {
throw runtime_error("cannot determine input format; use a filename ending with .json, .gsl, .gslb, or .afs");
}
auto cs = load_common_item_set(input_filename, args.get<bool>("big-endian"));
const string& output_filename = args.get<string>(2, false);
if (output_filename.empty()) {
cs->print(stdout);
} else {
auto json = cs->json();
string json_data = json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::HEX_INTEGERS | phosg::JSON::SerializeOption::SORT_DICT_KEYS);
string json_data = json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::SORT_DICT_KEYS);
write_output_data(args, json_data.data(), json_data.size(), "json");
}
});
Action a_compare_common_item_set(
"compare-common-item-set", nullptr,
+[](phosg::Arguments& args) {
string input_filename1 = args.get<string>(1, false);
if (input_filename1.empty() || (input_filename1 == "-")) {
throw runtime_error("two input filenames must be given");
}
string input_filename2 = args.get<string>(2, false);
if (input_filename2.empty() || (input_filename2 == "-")) {
throw runtime_error("two input filenames must be given");
}
auto cs1 = load_common_item_set(input_filename1, args.get<bool>("big-endian1"));
auto cs2 = load_common_item_set(input_filename2, args.get<bool>("big-endian2"));
cs1->print_diff(stdout, *cs2);
});
Action a_describe_item(
"describe-item", "\
@@ -2144,7 +2233,7 @@ Action a_describe_item(
}
string desc = name_index->describe_item(item);
string desc_colored = name_index->describe_item(item, true);
string desc_colored = name_index->describe_item(item, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
phosg::log_info_f("Data (decoded): {:02X}{:02X}{:02X}{:02X} {:02X}{:02X}{:02X}{:02X} {:02X}{:02X}{:02X}{:02X} -------- {:02X}{:02X}{:02X}{:02X}",
item.data1[0], item.data1[1], item.data1[2], item.data1[3],
@@ -2525,22 +2614,19 @@ Action a_generate_ep3_cards_html(
phosg::parallel_range<uint32_t>([&](uint32_t index, size_t) -> bool {
auto& info = this->card_infos[index];
if (!info.large_filename.empty()) {
phosg::Image img(info.large_filename);
phosg::Image cropped(512, 399);
cropped.blit(img, 0, 0, 512, 399, 0, 0);
info.large_data_url = cropped.png_data_url();
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(info.large_filename));
img.resize(512, 399);
info.large_data_url = img.serialize(phosg::ImageFormat::PNG_DATA_URL);
}
if (!info.medium_filename.empty()) {
phosg::Image img(info.medium_filename);
phosg::Image cropped(184, 144);
cropped.blit(img, 0, 0, 184, 144, 0, 0);
info.medium_data_url = cropped.png_data_url();
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(info.medium_filename));
img.resize(184, 144);
info.medium_data_url = img.serialize(phosg::ImageFormat::PNG_DATA_URL);
}
if (!info.small_filename.empty()) {
phosg::Image img(info.small_filename);
phosg::Image cropped(58, 43);
cropped.blit(img, 0, 0, 58, 43, 0, 0);
info.small_data_url = cropped.png_data_url();
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(info.small_filename));
img.resize(58, 43);
info.small_data_url = img.serialize(phosg::ImageFormat::PNG_DATA_URL);
}
return false;
},
@@ -2723,17 +2809,17 @@ Action a_show_battle_params(
s->load_battle_params();
phosg::fwrite_fmt(stdout, "Episode 1 multi\n");
s->battle_params->get_table(false, Episode::EP1).print(stdout);
s->battle_params->get_table(false, Episode::EP1).print(stdout, Episode::EP1);
phosg::fwrite_fmt(stdout, "Episode 1 solo\n");
s->battle_params->get_table(true, Episode::EP1).print(stdout);
s->battle_params->get_table(true, Episode::EP1).print(stdout, Episode::EP1);
phosg::fwrite_fmt(stdout, "Episode 2 multi\n");
s->battle_params->get_table(false, Episode::EP2).print(stdout);
s->battle_params->get_table(false, Episode::EP2).print(stdout, Episode::EP2);
phosg::fwrite_fmt(stdout, "Episode 2 solo\n");
s->battle_params->get_table(true, Episode::EP2).print(stdout);
s->battle_params->get_table(true, Episode::EP2).print(stdout, Episode::EP2);
phosg::fwrite_fmt(stdout, "Episode 4 multi\n");
s->battle_params->get_table(false, Episode::EP4).print(stdout);
s->battle_params->get_table(false, Episode::EP4).print(stdout, Episode::EP4);
phosg::fwrite_fmt(stdout, "Episode 4 solo\n");
s->battle_params->get_table(true, Episode::EP4).print(stdout);
s->battle_params->get_table(true, Episode::EP4).print(stdout, Episode::EP4);
});
Action a_check_supermaps(
@@ -3182,6 +3268,9 @@ Action a_run_server_replay_log(
}
auto state = make_shared<ServerState>(get_config_filename(args));
if (args.get<bool>("debug")) {
state->is_debug = true;
}
state->load_all(true);
if (state->dns_server_port) {
+15 -66
View File
@@ -972,7 +972,11 @@ static const vector<DATEntityDefinition> dat_object_definitions({
// In offline mode, this object constructs TObjWarpBossMulti instead.
{0x0019, F_V0_V4, 0x00006FFC3FFC04A5, "TObjWarpBoss"},
// Sign board. This shows the loaded image from a quest (via load_pvr).
// Sign board. This shows the loaded image from a quest (via load_pvr). On
// the final version of PCv2, this object doesn't render at all; my guess
// is that Sega hardcoded the PVR filenames for the various events in the
// executable, then after those events ended, they just deleted the
// load_pvr code entirely, leaving this object nonfunctional.
// Params:
// param1-3 = scale factors (x, y, z)
{0x001A, F_V1_V4, 0x0000600000040001, "TObjSinBoard"},
@@ -2720,8 +2724,8 @@ static const vector<DATEntityDefinition> dat_enemy_definitions({
{0x0110, F_EP3, 0x0000000000000001, "TObjNpcWalkingMeka_Hero"}, // Small talking robot in Morgue
{0x0111, F_EP3, 0x0000000000000001, "TObjNpcWalkingMeka_Dark"}, // Small talking robot in Morgue
// Episode 3 scientist and aide NPCs. These NPC take all the same params as
// the NPCs defined above, but also:
// Episode 3 scientist and aide NPCs. These NPCs take all the same params
// as the NPCs defined above, but also:
// angle.x = model number (clamped to [0, 3] for scientists, [0, 2] for
// aides)
// The two type values for scientists (00D4 and 00D5) are direct aliases
@@ -2927,7 +2931,7 @@ static const vector<DATEntityDefinition> dat_enemy_definitions({
// Monest that has param1 = 3 and param2 = 10. This looks like just an
// off-by-one error on Sega's part where they accidentally shifted the
// parameters down by one place. As described above, this Monest expels
// 6 Mothmants, then no more after they are killed.
// 6 Mothmants immediately, then no more after those 6 are killed.
{0x0042, F_V0_V4, 0x0000000000180006, "TObjEneBm3FlyNest"},
// Savage Wolf or Barbarous Wolf. Params:
@@ -5848,55 +5852,12 @@ uint32_t MapState::RareEnemyRates::for_enemy_type(EnemyType type) const {
}
}
const shared_ptr<const MapState::RareEnemyRates> MapState::NO_RARE_ENEMIES = make_shared<MapState::RareEnemyRates>(
0, 0, 0);
const shared_ptr<const MapState::RareEnemyRates> MapState::NO_RARE_ENEMIES = make_shared<MapState::RareEnemyRates>(0, 0, 0);
const shared_ptr<const MapState::RareEnemyRates> MapState::DEFAULT_RARE_ENEMIES = make_shared<MapState::RareEnemyRates>(
MapState::RareEnemyRates::DEFAULT_RARE_ENEMY_RATE_V3,
MapState::RareEnemyRates::DEFAULT_MERICARAND_RATE_V3,
MapState::RareEnemyRates::DEFAULT_RARE_BOSS_RATE_V4);
uint32_t MapState::EnemyState::convert_game_flags(uint32_t game_flags, bool to_v3) {
// The format of game_flags was changed significantly between v2 and v3, and
// not accounting for this results in odd effects like other characters not
// appearing when joining a game. Unfortunately, some bits were deleted on v3
// and other bits were added, so it doesn't suffice to simply store the most
// complete format of this field - we have to be able to convert between the
// two.
// Bits on v2: ?IHCBAzy xwvutsrq ponmlkji hgfedcba
// Bits on v3: ?IHGFEDC BAzyxwvu srqponkj hgfedcba
// The bits ilmt were removed in v3 and the bits to their left were shifted
// right. The bits DEFG were added in v3 and do not exist on v2.
// Known meanings for these bits:
// o = is dead
// n = should play hit animation
// y = is near enemy
// H = is enemy?
// I = is object? (some entities have both H and I set though)
// TODO: The above might all be wrong.
// GC 00100000 10010000 00001110 00000000
// PC 00101001 00000000 01100100 00000000
// PC 00101001 10110000 00101110 00000000
// GC 00100000 10011011 00000111 00000000
// PC 00101001 10010000 00101110 00000000
// GC 00100000 10011001 00000111 00000000
if (to_v3) {
return (game_flags & 0xE00000FF) |
((game_flags & 0x00000600) >> 1) |
((game_flags & 0x0007E000) >> 3) |
((game_flags & 0x1FF00000) >> 4);
} else {
return (game_flags & 0xE00000FF) |
((game_flags << 1) & 0x00000600) |
((game_flags << 3) & 0x0007E000) |
((game_flags << 4) & 0x1FF00000);
}
}
MapState::EntityIterator::EntityIterator(MapState* map_state, Version version, bool at_end)
: map_state(map_state),
version(version),
@@ -6413,7 +6374,6 @@ void MapState::import_object_states_from_sync(
void MapState::import_enemy_states_from_sync(Version from_version, const SyncEnemyStateEntry* entries, size_t entry_count) {
this->log.info_f("Importing enemy state from sync command");
size_t enemy_index = 0;
bool is_v3 = !is_v1_or_v2(from_version);
for (const auto& fc : this->floor_config_entries) {
if (!fc.super_map) {
continue;
@@ -6434,15 +6394,10 @@ void MapState::import_enemy_states_from_sync(Version from_version, const SyncEne
if (ene_st->super_ene != ene) {
throw logic_error("super enemy link is incorrect");
}
if (ene_st->get_game_flags(is_v3) != entry.flags) {
this->log.warning_f("({:04X} => E-{:03X}) Flags from client ({:08X}({})) do not match game flags from map ({:08X}({}))",
enemy_index,
ene_st->e_id,
entry.flags,
is_v3 ? "v3" : "v2",
ene_st->game_flags,
(ene_st->server_flags & MapState::EnemyState::Flag::GAME_FLAGS_IS_V3) ? "v3" : "v2");
ene_st->set_game_flags(entry.flags, !is_v1_or_v2(from_version));
if (ene_st->game_flags != entry.flags) {
this->log.warning_f("({:04X} => E-{:03X}) Flags from client ({:08X}) do not match game flags from map ({:08X})",
enemy_index, ene_st->e_id, entry.flags, ene_st->game_flags);
ene_st->game_flags = entry.flags;
}
if (ene_st->total_damage != entry.total_damage) {
this->log.warning_f("({:04X} => E-{:03X}) Total damage from client ({}) does not match total damage from map ({})",
@@ -6771,14 +6726,8 @@ void MapState::print(FILE* stream) const {
}
}
string ene_str = ene_st->super_ene->str();
phosg::fwrite_fmt(stream, " {} total_damage={:04X} rare_flags={:04X} game_flags={:08X}({}) set_flags={:04X} server_flags={:04X}\n",
ene_str,
ene_st->total_damage,
ene_st->rare_flags,
ene_st->game_flags,
(ene_st->server_flags & MapState::EnemyState::Flag::GAME_FLAGS_IS_V3) ? "v3" : "v2",
ene_st->set_flags,
ene_st->server_flags);
phosg::fwrite_fmt(stream, " {} total_damage={:04X} rare_flags={:04X} game_flags={:08X} set_flags={:04X} server_flags={:04X}\n",
ene_str, ene_st->total_damage, ene_st->rare_flags, ene_st->game_flags, ene_st->set_flags, ene_st->server_flags);
}
if (this->bb_rare_enemy_indexes.empty()) {
-20
View File
@@ -716,7 +716,6 @@ public:
ITEM_DROPPED = 0x0008,
ALL_HITS_MASK_FIRST = 0x0010,
ALL_HITS_MASK = 0x00F0,
GAME_FLAGS_IS_V3 = 0x0100,
};
size_t e_id = 0;
size_t set_id = 0;
@@ -727,8 +726,6 @@ public:
uint16_t set_flags = 0; // Only used if super_ene->child_index == 0
uint16_t server_flags = 0;
static uint32_t convert_game_flags(uint32_t game_flags, bool to_v3);
inline void reset() {
this->total_damage = 0;
this->rare_flags = 0;
@@ -737,23 +734,6 @@ public:
this->server_flags = 0;
}
inline void set_game_flags(uint32_t game_flags, bool is_v3) {
this->game_flags = game_flags;
if (is_v3) {
this->server_flags |= Flag::GAME_FLAGS_IS_V3;
} else {
this->server_flags &= ~Flag::GAME_FLAGS_IS_V3;
}
}
inline uint32_t get_game_flags(bool is_v3) const {
bool flags_is_v3 = (this->server_flags & Flag::GAME_FLAGS_IS_V3);
if (flags_is_v3 == is_v3) {
return this->game_flags;
} else {
return this->convert_game_flags(this->game_flags, is_v3);
}
}
inline bool is_rare(Version version) const {
return (((this->rare_flags >> static_cast<size_t>(version)) & 1) ||
((version == Version::BB_V4) ? this->super_ene->is_default_rare_bb : this->super_ene->is_default_rare_v123));
+21 -20
View File
@@ -706,27 +706,28 @@ void PSOBBMultiKeyDetectorEncryption::encrypt(void* data, size_t size) {
}
void PSOBBMultiKeyDetectorEncryption::decrypt(void* data, size_t size) {
if (!this->active_crypt.get()) {
if (size != 8) {
throw logic_error("initial decryption size does not match expected first data size");
}
for (const auto& key : this->possible_keys) {
this->active_key = key;
this->active_crypt = make_shared<PSOBBEncryption>(*this->active_key, this->seed.data(), this->seed.size());
string test_data(reinterpret_cast<const char*>(data), size);
this->active_crypt->decrypt(test_data.data(), test_data.size());
if (this->expected_first_data.count(test_data)) {
break;
}
this->active_key.reset();
this->active_crypt.reset();
}
if (!this->active_crypt.get()) {
throw runtime_error("none of the registered private keys are valid for this client");
}
if (this->active_crypt.get()) {
this->active_crypt->decrypt(data, size);
return;
}
this->active_crypt->decrypt(data, size);
if (size != 8) {
throw logic_error("initial decryption size does not match expected first data size");
}
for (const auto& key : this->possible_keys) {
this->active_key = key;
this->active_crypt = make_shared<PSOBBEncryption>(*this->active_key, this->seed.data(), this->seed.size());
string test_data(reinterpret_cast<const char*>(data), size);
this->active_crypt->decrypt(test_data.data(), test_data.size());
if (this->expected_first_data.count(test_data)) {
memcpy(data, test_data.data(), size);
return;
}
this->active_key.reset();
this->active_crypt.reset();
}
throw runtime_error("none of the registered private keys are valid for this client");
}
PSOEncryption::Type PSOBBMultiKeyDetectorEncryption::type() const {
+16
View File
@@ -77,6 +77,10 @@ struct PlayerInventoryItemT {
ret.data.id.store_raw(phosg::bswap32(ret.data.id.load_raw()));
return ret;
}
bool is_equipped() const {
return (this->flags & 8);
}
} __attribute__((packed));
using PlayerInventoryItem = PlayerInventoryItemT<false>;
using PlayerInventoryItemBE = PlayerInventoryItemT<true>;
@@ -283,6 +287,12 @@ struct PlayerInventoryT {
}
}
void enforce_stack_limits(std::shared_ptr<const ItemData::StackLimits> stack_limits) {
for (size_t z = 0; z < std::min<uint8_t>(this->num_items, this->items.size()); z++) {
this->items[z].data.enforce_stack_size_limits(*stack_limits);
}
}
operator PlayerInventoryT<!BE>() const {
PlayerInventoryT<!BE> ret;
ret.num_items = this->num_items;
@@ -406,6 +416,12 @@ struct PlayerBankT {
}
}
void enforce_stack_limits(std::shared_ptr<const ItemData::StackLimits> stack_limits) {
for (size_t z = 0; z < std::min<uint8_t>(this->num_items, this->items.size()); z++) {
this->items[z].data.enforce_stack_size_limits(*stack_limits);
}
}
template <size_t DestSlotCount, bool DestBE>
operator PlayerBankT<DestSlotCount, DestBE>() const {
PlayerBankT<DestSlotCount, DestBE> ret;
+81 -1
View File
@@ -32,7 +32,21 @@ struct PlayerVisualConfigT {
/* 10 */ parray<uint8_t, 8> unknown_a2;
/* 18 */ U32T<BE> name_color = 0xFFFFFFFF; // ARGB
/* 1C */ uint8_t extra_model = 0;
/* 1D */ parray<uint8_t, 0x0F> unused;
// Some NPCs can crash the client if the character's class is incorrect. To
// handle this, we save the affected fields in the unused bytes after
// extra_model. This is a newserv-specific extension; it appears the
// following 15 bytes were simply never used by Sega.
/* 1D */ uint8_t npc_saved_data_type = 0;
/* 1E */ uint8_t npc_saved_costume = 0;
/* 1F */ uint8_t npc_saved_skin = 0;
/* 20 */ uint8_t npc_saved_face = 0;
/* 21 */ uint8_t npc_saved_head = 0;
/* 22 */ uint8_t npc_saved_hair = 0;
/* 23 */ uint8_t npc_saved_hair_r = 0;
/* 24 */ uint8_t npc_saved_hair_g = 0;
/* 25 */ uint8_t npc_saved_hair_b = 0;
/* 26 */ parray<uint8_t, 2> unused;
/* 28 */ F32T<BE> npc_saved_proportion_y = 0.0;
// See compute_name_color_checksum for details on how this is computed. If the
// value is incorrect, V1 and V2 will ignore the name_color field and use the
// default color instead. This field is ignored on GC; on BB (and presumably
@@ -81,6 +95,72 @@ struct PlayerVisualConfigT {
this->name_color_checksum = this->compute_name_color_checksum(this->name_color);
}
void backup_npc_saved_fields() {
if (this->npc_saved_data_type == 0x8E) {
return;
}
// Restore old-format data if needed before backing up again
this->restore_npc_saved_fields();
this->npc_saved_data_type = 0x8E;
this->npc_saved_costume = this->costume;
this->npc_saved_skin = this->skin;
this->npc_saved_face = this->face;
this->npc_saved_head = this->head;
this->npc_saved_hair = this->hair;
this->npc_saved_hair_r = this->hair_r;
this->npc_saved_hair_g = this->hair_g;
this->npc_saved_hair_b = this->hair_b;
this->npc_saved_proportion_y = this->proportion_y;
this->costume = 0;
this->skin = 0;
this->face = 0;
this->head = 0;
this->hair = 0;
this->hair_r = 0;
this->hair_g = 0;
this->hair_b = 0;
this->proportion_y = 0;
}
void restore_npc_saved_fields() {
switch (this->npc_saved_data_type) {
case 0x00:
break;
case 0x8D: // Old format
this->char_class = this->npc_saved_costume;
this->head = this->npc_saved_skin;
this->hair = this->npc_saved_face;
break;
case 0x8E: // New format
this->costume = this->npc_saved_costume;
this->skin = this->npc_saved_skin;
this->face = this->npc_saved_face;
this->head = this->npc_saved_head;
this->hair = this->npc_saved_hair;
this->hair_r = this->npc_saved_hair_r;
this->hair_g = this->npc_saved_hair_g;
this->hair_b = this->npc_saved_hair_b;
this->proportion_y = this->npc_saved_proportion_y;
break;
default:
throw std::runtime_error("unknown saved NPC data format");
}
this->npc_saved_data_type = 0;
this->npc_saved_costume = 0;
this->npc_saved_skin = 0;
this->npc_saved_face = 0;
this->npc_saved_head = 0;
this->npc_saved_hair = 0;
this->npc_saved_hair_r = 0;
this->npc_saved_hair_g = 0;
this->npc_saved_hair_b = 0;
this->unused.clear(0);
this->npc_saved_proportion_y = 0.0;
}
void enforce_lobby_join_limits_for_version(Version v) {
struct ClassMaxes {
uint16_t costume;
+44 -30
View File
@@ -236,7 +236,7 @@ static asio::awaitable<HandlerResult> S_G_9A(shared_ptr<Client> c, Channel::Mess
// right after the client config data
c->proxy_session->server_channel->send(
0x9E, 0x01, &cmd,
cmd.is_extended ? sizeof(C_LoginExtended_GC_9E) : sizeof(C_Login_GC_9E));
cmd.is_extended ? sizeof(C_LoginExtended_GC_9E) : sizeof(C_Login_PC_GC_9E));
co_return HandlerResult::SUPPRESS;
}
@@ -356,11 +356,11 @@ static asio::awaitable<HandlerResult> S_B_03(shared_ptr<Client> c, Channel::Mess
resp.character_slot = c->bb_character_index;
resp.connection_phase = c->bb_connection_phase;
resp.client_code = c->bb_client_code;
resp.security_token = c->proxy_session->remote_bb_security_token;
resp.security_token = c->bb_security_token;
resp.username.encode(c->username, c->language());
resp.password.encode(c->password, c->language());
resp.hardware_id = c->hardware_id;
resp.client_config = c->proxy_session->remote_client_config_data;
resp.client_config = c->bb_client_config;
if (c->proxy_session->enable_remote_ip_crc_patch) {
*reinterpret_cast<le_uint32_t*>(resp.client_config.data() + 0x10) =
c->proxy_session->remote_ip_crc ^ (1309539928UL + 1248334810UL);
@@ -373,27 +373,17 @@ static asio::awaitable<HandlerResult> S_B_03(shared_ptr<Client> c, Channel::Mess
static asio::awaitable<HandlerResult> S_B_E6(shared_ptr<Client> c, Channel::Message& msg) {
const auto& cmd = msg.check_size_t<S_ClientInit_BB_00E6>(0xFFFF);
c->proxy_session->remote_guild_card_number = cmd.guild_card_number;
c->proxy_session->remote_bb_security_token = cmd.security_token;
c->proxy_session->remote_client_config_data = cmd.client_config;
c->bb_security_token = cmd.security_token;
c->bb_client_config = cmd.client_config;
auto s = c->require_server_state();
auto& pc = s->proxy_persistent_configs[c->login->account->account_id];
pc.account_id = c->login->account->account_id;
pc.remote_guild_card_number = c->proxy_session->remote_guild_card_number;
pc.remote_bb_security_token = c->proxy_session->remote_bb_security_token;
pc.remote_client_config_data = c->proxy_session->remote_client_config_data;
pc.enable_remote_ip_crc_patch = c->proxy_session->enable_remote_ip_crc_patch;
c->log.info_f("Updated persistent config for proxy session");
if ((c->bb_connection_phase == 0) && c->proxy_session->received_reconnect) {
c->proxy_session->server_channel->send(0x00E0); // Request system file
}
co_return HandlerResult::SUPPRESS;
}
static asio::awaitable<HandlerResult> C_B_E0(shared_ptr<Client>, Channel::Message&) {
co_return HandlerResult::SUPPRESS;
co_return HandlerResult::FORWARD;
}
static asio::awaitable<HandlerResult> S_V123_04(shared_ptr<Client> c, Channel::Message& msg) {
@@ -434,10 +424,7 @@ static asio::awaitable<HandlerResult> S_V123_04(shared_ptr<Client> c, Channel::M
// If there was previously a guild card number, assume we got the lobby server
// init text instead of the port map init text.
memcpy(c->proxy_session->remote_client_config_data.data(),
had_guild_card_number
? "t Lobby Server. Copyright SEGA E"
: "t Port Map. Copyright SEGA Enter",
0x20);
had_guild_card_number ? "t Lobby Server. Copyright SEGA E" : "t Port Map. Copyright SEGA Enter", 0x20);
memcpy(c->proxy_session->remote_client_config_data.data(), &cmd.client_config,
min<size_t>(msg.data.size() - offsetof(S_UpdateClientConfig_V3_04, client_config),
c->proxy_session->remote_client_config_data.bytes()));
@@ -688,6 +675,12 @@ static asio::awaitable<HandlerResult> C_B3(shared_ptr<Client> c, Channel::Messag
}
}
static asio::awaitable<HandlerResult> C_B_E0(shared_ptr<Client> c, Channel::Message&) {
auto ret = c->proxy_session->bb_client_sent_E0 ? HandlerResult::FORWARD : HandlerResult::SUPPRESS;
c->proxy_session->bb_client_sent_E0 = true;
co_return ret;
}
static asio::awaitable<HandlerResult> S_B_E2(shared_ptr<Client> c, Channel::Message& msg) {
if (c->check_flag(Client::Flag::PROXY_SAVE_FILES)) {
string output_filename = std::format("system.{}.psosys", phosg::now());
@@ -748,18 +741,18 @@ static asio::awaitable<HandlerResult> S_G_E4(shared_ptr<Client> c, Channel::Mess
static asio::awaitable<HandlerResult> S_B_22(shared_ptr<Client> c, Channel::Message& msg) {
// We use this command (which is sent before the init encryption command) to
// detect a particular server behavior that we'll have to work around later.
// It looks like this command's existence is another anti-proxy measure, since
// It looks like this command's existence is an anti-proxy measure, since
// this command is 0x34 bytes in total, and the logic that adds padding bytes
// when the command size isn't a multiple of 8 is only active when encryption
// is enabled. Presumably some simpler proxies would get this wrong.
// Editor's note: There's an unsavory message in this command's data field,
// hence the hash here instead of a direct string comparison. I'd love to hear
// the story behind why they put that string there.
// hence the hash here instead of a direct string comparison. I'd love to
// hear the story behind why they put that string there.
if ((msg.data.size() == 0x2C) && (phosg::fnv1a64(msg.data.data(), msg.data.size()) == 0x8AF8314316A27994)) {
c->log.info_f("Enabling remote IP CRC patch");
c->proxy_session->enable_remote_ip_crc_patch = true;
}
co_return HandlerResult::FORWARD;
co_return HandlerResult::SUPPRESS;
}
static asio::awaitable<HandlerResult> S_19_U_14(shared_ptr<Client> c, Channel::Message& msg) {
@@ -789,6 +782,9 @@ static asio::awaitable<HandlerResult> S_19_U_14(shared_ptr<Client> c, Channel::M
if (is_patch(c->version())) {
auto& cmd = msg.check_size_t<S_Reconnect_Patch_14>();
new_ep = make_endpoint_ipv4(cmd.address, cmd.port);
} else if (msg.flag == 6 && msg.data.size() >= sizeof(S_ReconnectIPv6_Extension_19)) {
auto& cmd = msg.check_size_t<S_ReconnectIPv6_Extension_19>(0xFFFF);
new_ep = make_endpoint_ipv6(cmd.address.data(), cmd.port);
} else {
// This weird maximum size is here to properly handle the version-split
// command that some servers (including newserv) use on port 9100
@@ -894,7 +890,7 @@ static asio::awaitable<HandlerResult> SC_6x60_6xA2(shared_ptr<Client> c, Channel
c->log.info_f("No item was created");
} else {
auto s = c->require_server_state();
string name = s->describe_item(c->version(), res.item, false);
string name = s->describe_item(c->version(), res.item);
c->log.info_f("Entity {:04X} (area {:02X}) created item {}", cmd.entity_index, cmd.effective_area, name);
res.item.id = c->proxy_session->next_item_id++;
c->log.info_f("Creating item {:08X} at {:02X}:{:g},{:g} for all clients",
@@ -1557,7 +1553,7 @@ template <typename CmdT>
static asio::awaitable<HandlerResult> S_64(shared_ptr<Client> c, Channel::Message& msg) {
CmdT* cmd;
S_JoinGame_Ep3_64* cmd_ep3 = nullptr;
if (c->sub_version >= 0x40) {
if ((c->sub_version >= 0x40) && is_v3(c->version())) {
cmd = &msg.check_size_t<CmdT>(sizeof(S_JoinGame_Ep3_64));
cmd_ep3 = &msg.check_size_t<S_JoinGame_Ep3_64>();
} else if (c->version() == Version::XB_V3) {
@@ -1936,9 +1932,9 @@ asio::awaitable<HandlerResult> C_6x(shared_ptr<Client> c, Channel::Message& msg)
case 0x4A:
case 0x4B:
case 0x4C:
if (!is_v1(c->version()) && c->check_flag(Client::Flag::INFINITE_HP_ENABLED)) {
send_player_stats_change(c->channel, c->lobby_client_id, PlayerStatsChange::ADD_HP, 2550);
send_player_stats_change(c->proxy_session->server_channel, c->lobby_client_id, PlayerStatsChange::ADD_HP, 2550);
if (c->check_flag(Client::Flag::INFINITE_HP_ENABLED)) {
send_change_player_hp(c->channel, c->lobby_client_id, PlayerHPChange::MAXIMIZE_HP, 0);
send_change_player_hp(c->proxy_session->server_channel, c->lobby_client_id, PlayerHPChange::MAXIMIZE_HP, 0);
}
break;
@@ -1965,6 +1961,20 @@ asio::awaitable<HandlerResult> C_6x(shared_ptr<Client> c, Channel::Message& msg)
}
break;
case 0x4E: {
if (c->check_flag(Client::Flag::INFINITE_HP_ENABLED)) {
if (is_v1_or_v2(c->version()) && (c->version() != Version::GC_NTE)) {
G_UseMedicalCenter_6x31 cmd = {0x31, 0x01, c->lobby_client_id};
send_command_t(c->channel, 0x60, 0x00, cmd);
send_command_t(c->proxy_session->server_channel, 0x60, 0x00, cmd);
} else {
G_RevivePlayer_V3_BB_6xA1 cmd = {0xA1, 0x01, c->lobby_client_id};
co_await send_protected_command(c, &cmd, sizeof(cmd), true);
}
}
break;
}
case 0x5F:
send_item_notification_if_needed(
c, msg.check_size_t<G_DropItem_DC_6x5F>(sizeof(G_DropItem_PC_V3_BB_6x5F)).item.item, true);
@@ -2317,7 +2327,8 @@ asio::awaitable<void> on_proxy_command(shared_ptr<Client> c, bool from_server, u
}
}
asio::awaitable<void> handle_proxy_server_commands(shared_ptr<Client> c, shared_ptr<ProxySession> ses, shared_ptr<Channel> channel) {
asio::awaitable<void> handle_proxy_server_commands(
shared_ptr<Client> c, shared_ptr<ProxySession> ses, shared_ptr<Channel> channel) {
std::string error_str;
// server_channel can be changed by receiving a 19 command, hence the
// exception handler is inside the loop here
@@ -2326,6 +2337,9 @@ asio::awaitable<void> handle_proxy_server_commands(shared_ptr<Client> c, shared_
try {
msg = make_unique<Channel::Message>(co_await channel->recv());
if (c->proxy_session == ses) {
for (size_t z = 0; z < std::min<size_t>(c->proxy_session->prev_server_command_bytes.size(), msg->data.size()); z++) {
c->proxy_session->prev_server_command_bytes[z] = msg->data[z];
}
asio::co_spawn(co_await asio::this_coro::executor, on_proxy_command(c, true, std::move(msg)), asio::detached);
}
} catch (const std::system_error& e) {
-2
View File
@@ -10,8 +10,6 @@ ProxySession::ProxySession(shared_ptr<Channel> server_channel, const PersistentC
: server_channel(server_channel) {
if (pc) {
this->remote_guild_card_number = pc->remote_guild_card_number;
this->remote_bb_security_token = pc->remote_bb_security_token;
this->remote_client_config_data = pc->remote_client_config_data;
this->enable_remote_ip_crc_patch = pc->enable_remote_ip_crc_patch;
} else if (is_v4(this->server_channel->version)) {
this->remote_guild_card_number = 0;
+1 -3
View File
@@ -22,6 +22,7 @@ struct ProxySession {
uint32_t remote_ip_crc = 0;
bool received_reconnect = false;
bool enable_remote_ip_crc_patch = false;
bool bb_client_sent_E0 = false;
struct LobbyPlayer {
uint32_t guild_card_number = 0;
@@ -44,7 +45,6 @@ struct ProxySession {
uint64_t server_ping_start_time = 0;
int64_t remote_guild_card_number = -1;
uint32_t remote_bb_security_token = 0;
parray<uint8_t, 0x28> remote_client_config_data;
enum class DropMode {
@@ -64,8 +64,6 @@ struct ProxySession {
struct PersistentConfig {
uint32_t account_id;
uint32_t remote_guild_card_number;
uint32_t remote_bb_security_token;
parray<uint8_t, 0x28> remote_client_config_data;
bool enable_remote_ip_crc_patch;
std::unique_ptr<asio::steady_timer> expire_timer;
};
+49 -14
View File
@@ -830,8 +830,8 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
// regsA[0] = floor
// regsA[1] = section
// regsA[2] = group
{0x8A, "unhide_obj", nullptr, {{REG_SET_FIXED, 3}}, F_V0_V4},
{0x8B, "unhide_ene", nullptr, {{REG_SET_FIXED, 3}}, F_V0_V4},
{0x8A, "construct_delayed_object", "unhide_obj", {{REG_SET_FIXED, 3}}, F_V0_V4},
{0x8B, "construct_delayed_enemy", "unhide_ene", {{REG_SET_FIXED, 3}}, F_V0_V4},
// Starts a new thread when the player is close enough to the given point.
// The collision is created on the current floor; the thread is created
@@ -991,7 +991,12 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
{0xB6, "item_delete_by_type", "item_delete2", {{REG_SET_FIXED, 3}, {REG_SET_FIXED, 12}}, F_V0_V4},
// Searches the player's inventory for an item and returns its item ID.
// regsA[0-2] = item.data1[0-2] to search for
// The matching condition depends on the item's type:
// Weapons: data1[0-2] must match, and data1[4] (special/flags) must be 0
// Armor/shield/unit: data1[0-2] must match
// Mag: data1[0-1] must match; regsA[2] is ignored
// Tool: data1[0-2] must match; if it's a tech disk, data1[4] must be 0
// regsA[0-2] = item.data1[0-2] to search for, as above
// regB = found item ID, or FFFFFFFF if not found
{0xB7, "find_inventory_item", "item_check", {{REG_SET_FIXED, 3}, REG}, F_V0_V4},
@@ -1130,8 +1135,10 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
{0xD0, "pl_pkon", nullptr, {}, F_V1_V4},
// Like find_inventory_item, but regsA specifies data1[0-2] as well as
// data1[4]. Returns the item ID in regB, or FFFFFFFF if not found.
{0xD1, "pl_chk_item2", nullptr, {{REG_SET_FIXED, 4}, REG}, F_V1_V4},
// data1[4]. The matching conditions are the same as in find_inventory_item
// except that data1[4] must match regsA[3], instead of zero. Returns the
// item ID in regB, or FFFFFFFF if not found.
{0xD1, "find_inventory_item_ex", "pl_chk_item2", {{REG_SET_FIXED, 4}, REG}, F_V1_V4},
// Enables/disables the main menu and shortcut menu.
{0xD2, "enable_mainmenu", nullptr, {}, F_V1_V4},
@@ -1171,9 +1178,9 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
{0xDD, "load_midi", nullptr, {}, F_V1_V4},
// Finds an item in the player's bank, and clears its entry in the bank.
// regsA[0-5] = item.data1[0-5]
// regsA[0-5] = item.data1[0-5] (bank item must exactly match all bytes)
// regB = 1 if item was found and cleared, 0 if not
{0xDE, "item_detect_bank", "unknownDE", {{REG_SET_FIXED, 6}, REG}, F_V1_V4},
{0xDE, "delete_bank_item", "unknownDE", {{REG_SET_FIXED, 6}, REG}, F_V1_V4},
// Sets NPC AI behaviors.
// regsA[0] = unknown (TODO)
@@ -1628,8 +1635,8 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
// Creates an S-rank weapon in the player's inventory. This opcode is not
// used in challenge mode, presumably since it doesn't offer a mechanism
// for the player to choose their weapon's name. The award_item_give_to
// opcode is used instead.
// for the player to choose their weapon's name. The award_item_give opcode
// is used instead.
// regA/valueA = client ID (must match local client ID)
// regB (must be a register, even on v3/v4) = item.data1[1]
// strC = custom name
@@ -2003,7 +2010,7 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
// Returns the local player's battle mode records. The values returned are
// the first 7 fields of the PlayerRecordsBattle structure (see
// PlayerSubordinates.hh). These are:
// regsA[0-3] = number of times placed 1st, 2nd, 3rd, 4th respectively
// regsA[0-3] = number of times placed 1st, 2nd, 3rd, and 4th, respectively
// regsA[4] = number of disconnects
// regsA[5-6] = unknown (TODO)
{0xF8AB, "get_ba_record", nullptr, {{REG_SET_FIXED, 7}}, F_V2_V4},
@@ -2088,11 +2095,38 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
// is the last opcode implemented before v3.
{0xF8BB, "write_flag_buf_to_event_flags2", "unknownF8BB", {REG}, F_V2_V4},
// Returns (in regB) the Guild Card number of the player in the slot
// specified by regA. If there is no player in that slot, returns FFFFFFFF.
// This opcode is only implemented on certain later versions of PC v2, and
// not on any v3 or later versions.
{0xF8BC, "get_player_guild_card_number", nullptr, {REG, REG}, F_PC_V2},
// Sets the current episode. Must be used in the start label. valueA should
// be 0 for Episode 1 (which is the default), 1 for Episode 2, or 2 for
// Episode 4 (BB only).
{0xF8BC, "set_episode", nullptr, {INT32}, F_V3_V4 | F_SET_EPISODE},
// This opcode returns (in regsB) the full symbol chat data for the symbol
// chat currently being said by the player specified in regA. The symbol
// chat data is only returned for 120 frames (4 seconds) after the
// corresponding 6x07 command is received; after that, this opcode will
// return a blank symbol chat instead. This opcode only works if
// create_symbol_chat_monitor is run first.
// This opcode is only implemented on certain later versions of PC v2, and
// not on any v3 or later versions.
{0xF8BD, "get_current_symbol_chat", nullptr, {REG, {REG_SET_FIXED, 15}}, F_PC_V2}, // TODO: Document args
// This opcode is enables the usage of get_current_symbol_chat.
// This opcode is only implemented on certain later versions of PC v2, and
// not on any v3 or later versions.
{0xF8BE, "create_symbol_chat_monitor", nullptr, {}, F_PC_V2},
// This opcode causes the client to immediately save the PSO______COM
// (system) and PSO______GUD (Guild Card) files to disk.
// This opcode is only implemented on certain later versions of PC v2, and
// not on any v3 or later versions.
{0xF8BF, "save_system_and_gc_files", nullptr, {}, F_PC_V2},
// Requests a file from the server by sending a D7 command. valueA
// specifies header.flag, strB is the file name (up to 16 characters).
// This opcode works on Xbox, but the GBA opcodes do not, so it's
@@ -2353,7 +2387,7 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
// regsA[1-3] = item.data1[0-2]
// regB = returned amount of item present in player's inventory
// If the item is not present, returns 0.
{0xF911, "get_item_count", "get_stackable_item_count", {{REG_SET_FIXED, 4}, REG}, F_V3_V4},
{0xF911, "get_stackable_item_count", "get_item_count", {{REG_SET_FIXED, 4}, REG}, F_V3_V4},
// Freezes a character and hides their equips, or does the opposite.
// Internally, this toggles the disable-update flag on TL_03.
@@ -2460,11 +2494,12 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
// valueB = value to write
{0xF926, "write_counter", "write_global_flag", {INT32, INT32}, F_V3_V4 | F_ARGS},
// Checks if an item exists in the local player's bank.
// Checks if an item exists in the local player's bank. The matching logic
// is the same as in find_inventory_item.
// regsA[0-2] = item.data1[0-2]
// regsA[3] = item.data1[4]
// regB = 1 if item was found, 0 if not
{0xF927, "item_detect_bank2", "item_check_bank", {{REG_SET_FIXED, 4}, REG}, F_V3_V4},
{0xF927, "find_bank_item", "item_check_bank", {{REG_SET_FIXED, 4}, REG}, F_V3_V4},
// Returns whether each player is present.
// regsA[0-3] = returned flags (for each player: 0 if absent, 1 if present)
@@ -2486,7 +2521,7 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
// Returns the item chosen by the player in an open_pack_select window, or
// FFFFFFFF if they canceled it.
{0xF92C, "get_item_id", nullptr, {REG}, F_V3_V4},
{0xF92C, "get_chosen_item_id", "get_item_id", {REG}, F_V3_V4},
// Adds a color overlay on the player's screen. The overlay fades in
// linearly over the given number of frames. The overlay is not deleted
+1 -1
View File
@@ -722,7 +722,7 @@ string RareItemSet::serialize_html(
}
string hex = example_item.short_hex();
string desc = name_index->describe_item(example_item, false, true);
string desc = name_index->describe_item(example_item, ItemNameIndex::Flag::NAME_ONLY);
tokens.emplace_back(std::format("<span class=\"item\" title=\"Hex: {}\">{}</span>", hex, desc));
float denom = static_cast<float>(frac.second) / static_cast<double>(frac.first);
+81 -49
View File
@@ -43,18 +43,14 @@ asio::awaitable<void> on_connect(std::shared_ptr<Client> c) {
uint16_t pc_port = s->name_to_port_config.at("pc")->port;
uint16_t console_port = s->name_to_port_config.at("gc-us3")->port;
send_pc_console_split_reconnect(c, s->connect_address_for_client(c), pc_port, console_port);
// TODO: There appears to be a bug that occurs rarely when an IPSSClient
// TODO: There appears to be a bug that occurs rarely when a client
// connects to this port; sometimes it disconnects before receiving the
// data it needs. My hypothesis is that there's either a bug in
// IPSSClient where the data isn't being sent before the RST, or there's
// a bug in AVE-TCP where it doesn't forward the last data to the app if
// the RST is received on the same frame as the last PSH. In either case,
// waiting a short amount of time here should mitigate it. This doesn't
// seem to happen at all with SocketChannel, so we only do it for
// IPSSChannel.
if (dynamic_pointer_cast<IPSSChannel>(c->channel)) {
co_await async_sleep(std::chrono::seconds(1));
}
// data it needs. My hypothesis is that there's either a bug in Channel
// where the data isn't being sent before the RST, or there's a bug in
// AVE-TCP where it doesn't forward the last data to the app if the RST
// is received on the same frame as the last PSH. In either case, waiting
// a short amount of time here should mitigate it.
co_await async_sleep(std::chrono::seconds(2));
c->channel->disconnect();
break;
}
@@ -236,7 +232,8 @@ static asio::awaitable<void> send_auto_patches_if_needed(shared_ptr<Client> c) {
auto s = c->require_server_state();
if (c->login->account->auto_patches_enabled.empty() &&
((c->version() != Version::BB_V4) || s->bb_required_patches.empty())) {
((c->version() != Version::BB_V4) || s->bb_required_patches.empty()) &&
s->auto_patches.empty()) {
c->set_flag(Client::Flag::HAS_AUTO_PATCHES);
}
@@ -244,11 +241,11 @@ static asio::awaitable<void> send_auto_patches_if_needed(shared_ptr<Client> c) {
c->set_flag(Client::Flag::HAS_AUTO_PATCHES);
co_await prepare_client_for_patches(c);
vector<shared_ptr<const CompiledFunctionCode>> functions_to_send;
unordered_set<shared_ptr<const CompiledFunctionCode>> functions_to_send;
if (c->version() == Version::BB_V4) {
for (const auto& patch_name : s->bb_required_patches) {
try {
functions_to_send.emplace_back(s->function_code_index->get_patch(patch_name, c->specific_version));
functions_to_send.emplace(s->function_code_index->get_patch(patch_name, c->specific_version));
} catch (const out_of_range&) {
string message = std::format(
"Your client is not compatible with a\nrequired patch on this server.\n\nClient version: {:08X}\nPatch name: {}", c->specific_version, patch_name);
@@ -258,9 +255,17 @@ static asio::awaitable<void> send_auto_patches_if_needed(shared_ptr<Client> c) {
}
}
}
for (const auto& patch_name : s->auto_patches) {
try {
functions_to_send.emplace(s->function_code_index->get_patch(patch_name, c->specific_version));
} catch (const out_of_range&) {
c->log.warning_f("Server has auto patch {} enabled, but it is not available for specific_version {:08X}",
patch_name, c->specific_version);
}
}
for (const auto& patch_name : c->login->account->auto_patches_enabled) {
try {
functions_to_send.emplace_back(s->function_code_index->get_patch(patch_name, c->specific_version));
functions_to_send.emplace(s->function_code_index->get_patch(patch_name, c->specific_version));
} catch (const out_of_range&) {
c->log.warning_f("Client has auto patch {} enabled, but it is not available for specific_version {:08X}",
patch_name, c->specific_version);
@@ -454,7 +459,7 @@ asio::awaitable<void> start_proxy_session(shared_ptr<Client> c, const string& ho
send_proxy_destinations_menu(c);
}
} else {
// Get persistent config if client is BB
// Get persistent config if available
ProxySession::PersistentConfig* pc = nullptr;
if (use_persistent_config) {
try {
@@ -477,8 +482,8 @@ asio::awaitable<void> start_proxy_session(shared_ptr<Client> c, const string& ho
std::format("C-{} proxy remote server at {}", c->id, netloc_str),
phosg::TerminalFormat::FG_YELLOW,
phosg::TerminalFormat::FG_RED);
c->proxy_session = make_shared<ProxySession>(channel, pc);
c->log.info_f("Server channel connected");
asio::co_spawn(*s->io_context, handle_proxy_server_commands(c, c->proxy_session, channel), asio::detached);
}
@@ -507,15 +512,6 @@ asio::awaitable<void> end_proxy_session(shared_ptr<Client> c, const std::string&
} catch (const out_of_range&) {
}
bool is_in_game = c->proxy_session->is_in_game;
c->proxy_session->server_channel->disconnect();
c->proxy_session.reset();
if (is_v4(c->version())) {
c->channel->disconnect();
co_return;
}
// Delete all the other players
for (size_t x = 0; x < c->proxy_session->lobby_players.size(); x++) {
if (c->proxy_session->lobby_players[x].guild_card_number == 0) {
@@ -527,6 +523,15 @@ asio::awaitable<void> end_proxy_session(shared_ptr<Client> c, const std::string&
c->channel->send(c->proxy_session->is_in_game ? 0x66 : 0x69, leaving_id, &cmd, sizeof(cmd));
}
bool is_in_game = c->proxy_session->is_in_game;
c->proxy_session->server_channel->disconnect();
c->proxy_session.reset();
if (is_v4(c->version())) {
c->channel->disconnect();
co_return;
}
if (is_in_game) {
string msg = std::format("You cannot return\nto $C6{}$C7\nwhile in a game.\n\n{}",
s->name, error_message);
@@ -1206,17 +1211,21 @@ static asio::awaitable<void> on_9D_9E(shared_ptr<Client> c, Channel::Message& ms
}
} else if (msg.command == 0x9E) {
const auto& cmd = check_size_t<C_Login_GC_9E>(msg.data, sizeof(C_LoginExtended_GC_9E));
base_cmd = &cmd;
if (cmd.is_extended) {
const auto& cmd = check_size_t<C_LoginExtended_GC_9E>(msg.data);
if (cmd.extension.lobby_refs[0].menu_id == MenuID::LOBBY) {
c->preferred_lobby_id = cmd.extension.lobby_refs[0].item_id;
auto handle_cmd = [&]<typename BaseCmdT, typename ExtendedCmdT>() {
const auto& cmd = check_size_t<BaseCmdT>(msg.data, sizeof(ExtendedCmdT));
base_cmd = &cmd;
if (cmd.is_extended) {
const auto& cmd = check_size_t<ExtendedCmdT>(msg.data);
if (cmd.extension.lobby_refs[0].menu_id == MenuID::LOBBY) {
c->preferred_lobby_id = cmd.extension.lobby_refs[0].item_id;
}
}
}
};
if (is_v3(c->version())) {
handle_cmd.template operator()<C_Login_PC_GC_9E, C_LoginExtended_GC_9E>();
c->set_flag(Client::Flag::AT_WELCOME_MESSAGE);
} else {
handle_cmd.template operator()<C_Login_PC_GC_9E, C_LoginExtended_PC_9E>();
}
} else {
@@ -1316,8 +1325,10 @@ static asio::awaitable<void> on_9D_9E(shared_ptr<Client> c, Channel::Message& ms
}
if (resp.checksum == 0x3677024C) {
c->specific_version = SPECIFIC_VERSION_PC_V2_DEFAULT;
c->log.info_f("Version detected as {:08X} from PE header checksum {:08X}",
c->specific_version, resp.checksum);
c->log.info_f("Version detected as {:08X} from PE header checksum {:08X}", c->specific_version, resp.checksum);
} else if (resp.checksum == 0x058BF2FF) {
c->specific_version = SPECIFIC_VERSION_PC_V2_FINAL;
c->log.info_f("Version detected as {:08X} from PE header checksum {:08X}", c->specific_version, resp.checksum);
} else {
c->specific_version = SPECIFIC_VERSION_PC_V2_INDETERMINATE;
c->log.info_f("Version cannot be determined from PE header checksum {:08X}", resp.checksum);
@@ -1480,24 +1491,34 @@ static asio::awaitable<void> on_93_BB(shared_ptr<Client> c, Channel::Message& ms
c->preferred_lobby_id = base_cmd.preferred_lobby_id;
}
send_client_init_bb(c, 0);
if (!c->bb_client_config.is_filled_with(0xFF)) {
if (base_cmd.guild_card_number == 0) {
// There is a (bug? feature?) in the BB client such that it has to receive
// a reconnect command during the data server phase, or else it won't know
// where to connect to during character selection. It's not clear why they
// didn't just make it use the initial connection address by default...
send_client_init_bb(c, 0);
send_reconnect(c, s->connect_address_for_client(c), s->name_to_port_config.at("bb-data1")->port);
co_return;
} else if (s->proxy_destination_bb.has_value()) {
// Start a proxy session if there's a destination configured Ignore the
// persistent config if this is the first data server connection, to
// prevent quick reconnects from incorrectly reusing the old session's
// state.
// Start a proxy session immediately if there's a destination set. Two
// things to watch out for:
// - Ignore the persistent config if this is the first data server
// connection, to prevent quick reconnects from incorrectly reusing the
// old session's state.
// - We don't send 00E6 (send_client_init_bb) in this case. This is because
// the login command is resent to the remote server, and we forward its
// response back to the client directly.
const auto& [host, port] = *s->proxy_destination_bb;
co_await start_proxy_session(c, host, port, c->bb_connection_phase != 0);
c->proxy_session->remote_client_config_data = c->bb_client_config;
co_return;
} else if (c->bb_connection_phase >= 0x04) {
} else {
send_client_init_bb(c, 0);
}
if (c->bb_connection_phase >= 0x04) {
// This means the client is done with the data server phase and is in the
// game server phase; we should send the ship select menu or a lobby join
// command.
@@ -2522,7 +2543,7 @@ static asio::awaitable<void> on_10_main_menu(shared_ptr<Client> c, uint32_t item
// don't send them from this mennu, because we need to know the
// client's specific_version before sending the menu.
co_await prepare_client_for_patches(c);
send_menu(c, c->require_server_state()->function_code_index->patch_switches_menu(c->specific_version, c->login->account->auto_patches_enabled));
send_menu(c, c->require_server_state()->function_code_index->patch_switches_menu(c->specific_version, s->auto_patches, c->login->account->auto_patches_enabled));
break;
}
@@ -2857,7 +2878,7 @@ static asio::awaitable<void> on_10_patch_switches(shared_ptr<Client> c, uint32_t
c->login->account->auto_patches_enabled.erase(fn->short_name);
}
c->login->account->save();
send_menu(c, s->function_code_index->patch_switches_menu(c->specific_version, c->login->account->auto_patches_enabled));
send_menu(c, s->function_code_index->patch_switches_menu(c->specific_version, s->auto_patches, c->login->account->auto_patches_enabled));
}
co_return;
}
@@ -3405,6 +3426,12 @@ static asio::awaitable<void> on_61_98(shared_ptr<Client> c, Channel::Message& ms
}
const auto* cmd3 = &check_size_t<C_CharacterData_Ep3_61_98>(msg.data);
c->ep3_config = make_shared<Episode3::PlayerConfig>(cmd3->ep3_config);
c->ep3_config->decrypt();
if (c->ep3_config->card_count_checksums_correct()) {
c->log.info_f("Card count checksums are correct");
} else {
c->log.info_f("Card count checksums are incorrect");
}
cmd = reinterpret_cast<const C_CharacterData_V3_61_98*>(cmd3);
if (specific_version_is_indeterminate(c->specific_version)) {
c->specific_version = SPECIFIC_VERSION_GC_EP3_JP; // 3SJ0
@@ -3519,15 +3546,21 @@ static asio::awaitable<void> on_30(shared_ptr<Client> c, Channel::Message& msg)
switch (c->version()) {
case Version::DC_V2:
ch = PSOBBCharacterFile::create_from_file(msg.check_size_t<PSODCV2CharacterFile::Character>());
ch->inventory.decode_from_client(c->version());
break;
case Version::GC_NTE:
ch = PSOBBCharacterFile::create_from_file(msg.check_size_t<PSOGCNTECharacterFileCharacter>());
ch->inventory.decode_from_client(c->version());
break;
case Version::GC_V3:
ch = PSOBBCharacterFile::create_from_file(msg.check_size_t<PSOGCCharacterFile::Character>());
// Note: We don't call ch->inventory.decode_from_client here because
// the data is sent in the game's native byte order, which is already
// correct on GC (unlike for 61/98)
break;
case Version::XB_V3:
ch = PSOBBCharacterFile::create_from_file(msg.check_size_t<PSOXBCharacterFileCharacter>());
ch = PSOBBCharacterFile::create_from_file(msg.check_size_t<PSOXBCharacterFile::Character>());
ch->inventory.decode_from_client(c->version());
break;
case Version::GC_EP3_NTE:
case Version::GC_EP3:
@@ -3541,7 +3574,6 @@ static asio::awaitable<void> on_30(shared_ptr<Client> c, Channel::Message& msg)
default:
throw logic_error("extended player data command not implemented for version");
}
ch->inventory.decode_from_client(c->version());
ch->disp.visual.version = 4;
ch->disp.visual.name_color_checksum = 0x00000000;
}
@@ -4082,7 +4114,7 @@ static asio::awaitable<void> on_DF_BB(shared_ptr<Client> c, Channel::Message& ms
award_state.rank_award_flags |= cmd.rank_bitmask;
p->add_item(cmd.item, *s->item_stack_limits(c->version()));
l->on_item_id_generated_externally(cmd.item.id);
string desc = s->describe_item(Version::BB_V4, cmd.item, false);
string desc = s->describe_item(Version::BB_V4, cmd.item);
l->log.info_f("(Challenge mode) Item awarded to player {}: {}", c->lobby_client_id, desc);
break;
}
+119 -73
View File
@@ -320,6 +320,10 @@ static asio::awaitable<void> on_invalid(shared_ptr<Client> c, SubcommandMessage&
co_return;
}
static asio::awaitable<void> on_debug_info(shared_ptr<Client>, SubcommandMessage&) {
co_return;
}
static asio::awaitable<void> on_forward_check_game_loading(shared_ptr<Client> c, SubcommandMessage& msg) {
auto l = c->require_lobby();
if (l->is_game() && l->any_client_loading()) {
@@ -1154,10 +1158,42 @@ G_6x70_Base_V1 Parsed6x70Data::base_v1(bool is_v3) const {
return ret;
}
uint32_t Parsed6x70Data::convert_game_flags(uint32_t game_flags, bool to_v3) {
// The format of game_flags for players was changed significantly between v2
// and v3, and not accounting for this results in odd effects like other
// characters not appearing when joining a game. Unfortunately, some bits
// were deleted on v3 and other bits were added, so it doesn't suffice to
// simply store the most complete format of this field - we have to be able
// to convert between the two.
// Bits on v2: ?IHCBAzy xwvutsrq ponmlkji hgfedcba
// Bits on v3: ?IHGFEDC BAzyxwvu srqponkj hgfedcba
// The bits ilmt were removed in v3 and the bits to their left were shifted
// right. The bits DEFG were added in v3 and do not exist on v2.
// Known meanings for these bits:
// o = is dead
// n = should play hit animation
// y = is near enemy
// H = is enemy?
// I = is object? (some entities have both H and I set though)
if (to_v3) {
return (game_flags & 0xE00000FF) |
((game_flags & 0x00000600) >> 1) |
((game_flags & 0x0007E000) >> 3) |
((game_flags & 0x1FF00000) >> 4);
} else {
return (game_flags & 0xE00000FF) |
((game_flags << 1) & 0x00000600) |
((game_flags << 3) & 0x0007E000) |
((game_flags << 4) & 0x1FF00000);
}
}
uint32_t Parsed6x70Data::get_game_flags(bool is_v3) const {
return (this->game_flags_is_v3 == is_v3)
? this->game_flags
: MapState::EnemyState::convert_game_flags(this->game_flags, is_v3);
: Parsed6x70Data::convert_game_flags(this->game_flags, is_v3);
}
static asio::awaitable<void> on_sync_joining_player_disp_and_inventory(
@@ -1648,10 +1684,9 @@ static asio::awaitable<void> on_player_revived(shared_ptr<Client> c, SubcommandM
auto l = c->require_lobby();
if (l->is_game()) {
forward_subcommand(c, msg);
bool player_cheats_enabled = !is_v1(c->version()) &&
(l->check_flag(Lobby::Flag::CHEATS_ENABLED) || (c->login->account->check_flag(Account::Flag::CHEAT_ANYWHERE)));
if (player_cheats_enabled && c->check_flag(Client::Flag::INFINITE_HP_ENABLED)) {
send_player_stats_change(c, PlayerStatsChange::ADD_HP, 2550);
if ((l->check_flag(Lobby::Flag::CHEATS_ENABLED) || (c->login->account->check_flag(Account::Flag::CHEAT_ANYWHERE))) &&
c->check_flag(Client::Flag::INFINITE_HP_ENABLED)) {
send_change_player_hp(l, c->lobby_client_id, PlayerHPChange::MAXIMIZE_HP, 0);
}
}
co_return;
@@ -1683,10 +1718,9 @@ static asio::awaitable<void> on_change_hp(shared_ptr<Client> c, SubcommandMessag
}
forward_subcommand(c, msg);
bool player_cheats_enabled = !is_v1(c->version()) &&
(l->check_flag(Lobby::Flag::CHEATS_ENABLED) || (c->login->account->check_flag(Account::Flag::CHEAT_ANYWHERE)));
if (player_cheats_enabled && c->check_flag(Client::Flag::INFINITE_HP_ENABLED)) {
send_player_stats_change(c, PlayerStatsChange::ADD_HP, 2550);
if ((l->check_flag(Lobby::Flag::CHEATS_ENABLED) || c->login->account->check_flag(Account::Flag::CHEAT_ANYWHERE)) &&
c->check_flag(Client::Flag::INFINITE_HP_ENABLED)) {
send_change_player_hp(l, c->lobby_client_id, PlayerHPChange::MAXIMIZE_HP, 0);
}
}
@@ -1917,7 +1951,7 @@ static asio::awaitable<void> on_player_drop_item(shared_ptr<Client> c, Subcomman
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} dropped item {:08X} ({}) at {}:({:g}, {:g})",
cmd.header.client_id, cmd.item_id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
c->print_inventory();
@@ -1955,7 +1989,7 @@ static asio::awaitable<void> on_create_inventory_item_t(shared_ptr<Client> c, Su
}
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} created inventory item {:08X} ({}) in inventory of NPC {:02X}; ignoring", c->lobby_client_id, item.id, name, cmd.header.client_id);
}
@@ -1963,7 +1997,7 @@ static asio::awaitable<void> on_create_inventory_item_t(shared_ptr<Client> c, Su
c->character()->add_item(item, *s->item_stack_limits(c->version()));
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} created inventory item {:08X} ({})", c->lobby_client_id, item.id, name);
c->print_inventory();
}
@@ -2006,7 +2040,7 @@ static void on_drop_partial_stack_t(shared_ptr<Client> c, SubcommandMessage& msg
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} split stack to create floor item {:08X} ({}) at {}:({:g},{:g})",
cmd.header.client_id, item.id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
c->print_inventory();
@@ -2061,7 +2095,7 @@ static asio::awaitable<void> on_drop_partial_stack_bb(shared_ptr<Client> c, Subc
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} split stack {:08X} (removed: {}) at {}:({:g}, {:g})",
cmd.header.client_id, cmd.item_id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
c->print_inventory();
@@ -2094,7 +2128,7 @@ static asio::awaitable<void> on_buy_shop_item(shared_ptr<Client> c, SubcommandMe
p->remove_meseta(price, c->version() != Version::BB_V4);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} bought item {:08X} ({}) from shop ({} Meseta)",
cmd.header.client_id, item.id, name, price);
c->print_inventory();
@@ -2126,7 +2160,7 @@ void send_item_notification_if_needed(shared_ptr<Client> c, const ItemData& item
}
if (should_notify) {
string name = s->describe_item(c->version(), item, true);
string name = s->describe_item(c->version(), item, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
const char* rare_header = (should_include_rare_header ? "$C6Rare item dropped:\n" : "");
send_text_message_fmt(c, "{}{}", rare_header, name);
}
@@ -2169,7 +2203,7 @@ static void on_box_or_enemy_item_drop_t(shared_ptr<Client> c, SubcommandMessage&
l->on_item_id_generated_externally(item.id);
l->add_item(cmd.item.floor, item, cmd.item.pos, obj_st, ene_st, should_notify ? 0x100F : 0x000F);
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} (leader) created floor item {:08X} ({}){} at {}:({:g}, {:g})",
l->leader_id,
item.id,
@@ -2218,8 +2252,7 @@ static asio::awaitable<void> on_pick_up_item_generic(
// This can happen if the network is slow, and the client tries to pick up
// the same item multiple times. Or multiple clients could try to pick up
// the same item at approximately the same time; only one should get it.
l->log.warning_f("Player {} requests to pick up {:08X}, but the item does not exist; dropping command",
client_id, item_id);
l->log.warning_f("Player {} requests to pick up {:08X}, but the item does not exist; dropping command", client_id, item_id);
} else {
// This is handled by the server on BB, and by the leader on other versions.
@@ -2249,7 +2282,7 @@ static asio::awaitable<void> on_pick_up_item_generic(
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), fi->data, false);
auto name = s->describe_item(c->version(), fi->data);
l->log.info_f("Player {} picked up {:08X} ({})", client_id, item_id, name);
c->print_inventory();
}
@@ -2266,8 +2299,7 @@ static asio::awaitable<void> on_pick_up_item_generic(
}
}
if (!c->login->account->check_user_flag(Account::UserFlag::DISABLE_DROP_NOTIFICATION_BROADCAST) &&
(fi->flags & 0x1000)) {
if (!c->login->account->check_user_flag(Account::UserFlag::DISABLE_DROP_NOTIFICATION_BROADCAST) && (fi->flags & 0x1000)) {
uint32_t pi = fi->data.primary_identifier();
bool should_send_game_notif, should_send_global_notif;
if (is_v1_or_v2(c->version()) && (c->version() != Version::GC_NTE)) {
@@ -2283,8 +2315,8 @@ static asio::awaitable<void> on_pick_up_item_generic(
if (should_send_game_notif || should_send_global_notif) {
string p_name = p->disp.name.decode();
string desc_ingame = s->describe_item(c->version(), fi->data, true);
string desc_http = s->describe_item(c->version(), fi->data, false);
string desc_ingame = s->describe_item(c->version(), fi->data, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
string desc_http = s->describe_item(c->version(), fi->data);
if (s->http_server) {
auto message = make_shared<phosg::JSON>(phosg::JSON::dict({
@@ -2377,7 +2409,7 @@ static asio::awaitable<void> on_use_item(shared_ptr<Client> c, SubcommandMessage
// Note: We do this weird scoping thing because player_use_item will
// likely delete the item, which will break the reference here.
const auto& item = p->inventory.items[index].data;
name = s->describe_item(c->version(), item, false);
name = s->describe_item(c->version(), item);
}
player_use_item(c, index, l->rand_crypt);
@@ -2408,9 +2440,9 @@ static asio::awaitable<void> on_feed_mag(shared_ptr<Client> c, SubcommandMessage
// Note: We do this weird scoping thing because player_feed_mag will
// likely delete the items, which will break the references here.
const auto& fed_item = p->inventory.items[fed_index].data;
fed_name = s->describe_item(c->version(), fed_item, false);
fed_name = s->describe_item(c->version(), fed_item);
const auto& mag_item = p->inventory.items[mag_index].data;
mag_name = s->describe_item(c->version(), mag_item, false);
mag_name = s->describe_item(c->version(), mag_item);
}
player_feed_mag(c, mag_index, fed_index);
@@ -2669,7 +2701,7 @@ static asio::awaitable<void> on_ep3_private_word_select_bb_bank_action(
send_destroy_item_to_lobby(c, cmd.item_id, cmd.item_amount, true);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
string name = s->describe_item(Version::BB_V4, item, false);
string name = s->describe_item(Version::BB_V4, item);
l->log.info_f("Player {} deposited item {:08X} (x{}) ({}) in the bank",
c->lobby_client_id, cmd.item_id, cmd.item_amount, name);
c->print_inventory();
@@ -2699,7 +2731,7 @@ static asio::awaitable<void> on_ep3_private_word_select_bb_bank_action(
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
string name = s->describe_item(Version::BB_V4, item, false);
string name = s->describe_item(Version::BB_V4, item);
l->log.info_f("Player {} withdrew item {:08X} (x{}) ({}) from the bank",
c->lobby_client_id, item.id, cmd.item_amount, name);
c->print_inventory();
@@ -2994,7 +3026,7 @@ static asio::awaitable<void> on_entity_drop_item_request(shared_ptr<Client> c, S
if (res.item.empty()) {
l->log.info_f("No item was created");
} else {
string name = s->describe_item(c->version(), res.item, false);
string name = s->describe_item(c->version(), res.item);
l->log.info_f("Entity {:04X} (area {:02X}) created item {}", cmd.entity_index, cmd.effective_area, name);
if (drop_mode == Lobby::DropMode::SERVER_DUPLICATE) {
for (const auto& lc : l->clients) {
@@ -3032,7 +3064,7 @@ static asio::awaitable<void> on_entity_drop_item_request(shared_ptr<Client> c, S
if (res.item.empty()) {
l->log.info_f("No item was created for {}", lc->channel->name);
} else {
string name = s->describe_item(lc->version(), res.item, false);
string name = s->describe_item(lc->version(), res.item);
l->log.info_f("Entity {:04X} (area {:02X}) created item {}", cmd.entity_index, cmd.effective_area, name);
res.item.id = l->generate_item_id(0xFF);
l->log.info_f("Creating item {:08X} at {:02X}:{:g},{:g} for {}",
@@ -3423,36 +3455,56 @@ static asio::awaitable<void> on_update_enemy_state(shared_ptr<Client> c, Subcomm
if ((cmd.enemy_index & 0xF000) || (cmd.header.entity_id != (cmd.enemy_index | 0x1000))) {
throw runtime_error("mismatched enemy id/index");
}
bool is_v3 = !is_v1_or_v2(c->version());
auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.enemy_index);
uint32_t src_flags = is_big_endian(c->version()) ? bswap32(cmd.game_flags) : cmd.game_flags.load();
if (l->difficulty == 3) {
src_flags = (src_flags & 0xFFFFFFC0) | (ene_st->get_game_flags(is_v3) & 0x0000003F);
src_flags = (src_flags & 0xFFFFFFC0) | (ene_st->game_flags & 0x0000003F);
}
ene_st->set_game_flags(src_flags, is_v3);
ene_st->game_flags = src_flags;
ene_st->total_damage = cmd.total_damage;
ene_st->set_last_hit_by_client_id(c->lobby_client_id);
l->log.info_f("E-{:03X} updated to damage={} game_flags={:08X} ({})",
ene_st->e_id,
ene_st->total_damage,
ene_st->game_flags,
(ene_st->server_flags & MapState::EnemyState::Flag::GAME_FLAGS_IS_V3) ? "v3" : "v2");
l->log.info_f("E-{:03X} updated to damage={} game_flags={:08X}", ene_st->e_id, ene_st->total_damage, ene_st->game_flags);
for (auto lc : l->clients) {
if (lc && (lc != c)) {
cmd.enemy_index = l->map_state->index_for_enemy_state(lc->version(), ene_st);
if (cmd.enemy_index != 0xFFFF) {
cmd.header.entity_id = 0x1000 | cmd.enemy_index;
uint32_t game_flags = ene_st->get_game_flags(!is_v1_or_v2(lc->version()));
cmd.game_flags = is_big_endian(lc->version()) ? phosg::bswap32(game_flags) : game_flags;
cmd.game_flags = is_big_endian(lc->version()) ? phosg::bswap32(ene_st->game_flags) : ene_st->game_flags;
send_command_t(lc, 0x60, 0x00, cmd);
}
}
}
}
static asio::awaitable<void> on_set_enemy_low_game_flags_ultimate(
shared_ptr<Client> c, SubcommandMessage& msg) {
static asio::awaitable<void> on_incr_enemy_damage(shared_ptr<Client> c, SubcommandMessage& msg) {
auto& cmd = msg.check_size_t<G_IncrementEnemyDamage_Extension_6xE4>();
if (command_is_private(msg.command)) {
co_return;
}
auto l = c->require_lobby();
if (!l->is_game()) {
co_return;
}
if (cmd.header.entity_id < 0x1000 || cmd.header.entity_id >= 0x4000) {
throw runtime_error("6xE4 received for non-enemy entity");
}
auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.header.entity_id & 0x0FFF);
c->log.info_f("E-{:03X} damage incremented by {}; before hit, damage was {} (cmd) or {} (ene_st) and HP was {}/{}",
ene_st->e_id,
cmd.hit_amount.load(),
ene_st->total_damage,
cmd.total_damage_before_hit.load(),
cmd.current_hp_before_hit.load(),
cmd.max_hp.load());
ene_st->total_damage = std::min<uint32_t>(ene_st->total_damage + cmd.hit_amount, cmd.max_hp);
co_await forward_subcommand_with_entity_id_transcode_t<G_IncrementEnemyDamage_Extension_6xE4>(c, msg);
}
static asio::awaitable<void> on_set_enemy_low_game_flags_ultimate(shared_ptr<Client> c, SubcommandMessage& msg) {
auto& cmd = msg.check_size_t<G_SetEnemyLowGameFlagsUltimate_6x9C>();
if (command_is_private(msg.command) ||
@@ -3467,15 +3519,10 @@ static asio::awaitable<void> on_set_enemy_low_game_flags_ultimate(
co_return;
}
bool is_v3 = !is_v1_or_v2(c->version());
auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.header.entity_id - 0x1000);
uint32_t game_flags = ene_st->get_game_flags(is_v3);
if (!(game_flags & cmd.low_game_flags)) {
ene_st->set_game_flags(game_flags | cmd.low_game_flags, is_v3);
l->log.info_f("E-{:03X} updated to game_flags={:08X} ({})",
ene_st->e_id,
ene_st->game_flags,
(ene_st->server_flags & MapState::EnemyState::Flag::GAME_FLAGS_IS_V3) ? "v3" : "v2");
if (!(ene_st->game_flags & cmd.low_game_flags)) {
ene_st->game_flags |= cmd.low_game_flags;
l->log.info_f("E-{:03X} updated to game_flags={:08X}", ene_st->e_id, ene_st->game_flags);
}
co_await forward_subcommand_with_entity_id_transcode_t<G_SetEnemyLowGameFlagsUltimate_6x9C>(c, msg);
@@ -3498,7 +3545,7 @@ static asio::awaitable<void> on_update_object_state_t(shared_ptr<Client> c, Subc
l->log.info_f("K-{:03X} updated with game_flags={:08X}", obj_st->k_id, obj_st->game_flags);
if ((cmd.object_index & 0xF000) || (cmd.header.entity_id != (cmd.object_index | 0x4000))) {
throw runtime_error("mismatched enemy id/index");
throw runtime_error("mismatched object id/index");
}
for (auto lc : l->clients) {
@@ -4009,7 +4056,7 @@ static asio::awaitable<void> on_item_reward_request_bb(shared_ptr<Client> c, Sub
ItemData item;
item = cmd.item_data;
item.enforce_min_stack_size(limits);
item.enforce_stack_size_limits(limits);
item.id = l->generate_item_id(c->lobby_client_id);
// The logic for the item_create and item_create2 opcodes (B3 and B4)
@@ -4027,7 +4074,7 @@ static asio::awaitable<void> on_item_reward_request_bb(shared_ptr<Client> c, Sub
c->character()->add_item(item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} created inventory item {:08X} ({}) via quest command",
c->lobby_client_id, item.id, name);
c->print_inventory();
@@ -4035,7 +4082,7 @@ static asio::awaitable<void> on_item_reward_request_bb(shared_ptr<Client> c, Sub
} catch (const out_of_range&) {
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} attempted to create inventory item {:08X} ({}) via quest command, but it cannot be placed in their inventory",
c->lobby_client_id, item.id, name);
}
@@ -4066,7 +4113,7 @@ asio::awaitable<void> on_transfer_item_via_mail_message_bb(shared_ptr<Client> c,
auto item = p->remove_item(cmd.item_id, cmd.amount, limits);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} sent inventory item {}:{:08X} ({}) x{} to player {:08X}",
c->lobby_client_id, cmd.header.client_id, cmd.item_id, name, cmd.amount, cmd.target_guild_card_number);
c->print_inventory();
@@ -4133,7 +4180,7 @@ static asio::awaitable<void> on_exchange_item_for_team_points_bb(shared_ptr<Clie
s->team_index->add_member_points(c->login->account->account_id, points);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} exchanged inventory item {}:{:08X} ({}) for {} team points",
c->lobby_client_id, cmd.header.client_id, cmd.item_id, name, points);
c->print_inventory();
@@ -4166,7 +4213,7 @@ static asio::awaitable<void> on_destroy_inventory_item(shared_ptr<Client> c, Sub
auto item = p->remove_item(cmd.item_id, cmd.amount, *s->item_stack_limits(c->version()));
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} destroyed inventory item {}:{:08X} ({})",
c->lobby_client_id, cmd.header.client_id, cmd.item_id, name);
c->print_inventory();
@@ -4218,7 +4265,7 @@ static asio::awaitable<void> on_destroy_floor_item(shared_ptr<Client> c, Subcomm
c->lobby_client_id, cmd.item_id);
} else {
auto name = s->describe_item(c->version(), fi->data, false);
auto name = s->describe_item(c->version(), fi->data);
l->log.info_f("Player {} destroyed floor item {:08X} ({})", c->lobby_client_id, cmd.item_id, name);
// Only forward to players for whom the item was visible
@@ -4324,7 +4371,7 @@ static asio::awaitable<void> on_sell_item_at_shop_bb(shared_ptr<Client> c, Subco
p->add_meseta(price);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} sold inventory item {:08X} ({}) for {} Meseta",
c->lobby_client_id, cmd.item_id, name, price);
c->print_inventory();
@@ -4367,9 +4414,8 @@ static asio::awaitable<void> on_buy_shop_item_bb(shared_ptr<Client> c, Subcomman
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
l->log.info_f("Player {} purchased item {:08X} ({}) for {} meseta",
c->lobby_client_id, item.id, name, price);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} purchased item {:08X} ({}) for {} meseta", c->lobby_client_id, item.id, name, price);
c->print_inventory();
}
co_return;
@@ -4671,7 +4717,7 @@ static asio::awaitable<void> on_quest_exchange_item_bb(shared_ptr<Client> c, Sub
// TODO: We probably should use an allow-list here to prevent the client
// from creating arbitrary items if cheat mode is disabled.
ItemData new_item = cmd.replace_item;
new_item.enforce_min_stack_size(limits);
new_item.enforce_stack_size_limits(limits);
new_item.id = l->generate_item_id(c->lobby_client_id);
p->add_item(new_item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
@@ -4729,7 +4775,7 @@ static asio::awaitable<void> on_photon_drop_exchange_for_item_bb(shared_ptr<Clie
// TODO: We probably should use an allow-list here to prevent the client
// from creating arbitrary items if cheat mode is disabled.
ItemData new_item = cmd.new_item;
new_item.enforce_min_stack_size(limits);
new_item.enforce_stack_size_limits(limits);
new_item.id = l->generate_item_id(c->lobby_client_id);
p->add_item(new_item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
@@ -4829,7 +4875,7 @@ static asio::awaitable<void> on_secret_lottery_ticket_exchange_bb(shared_ptr<Cli
ItemData item = (s->secret_lottery_results.size() == 1)
? s->secret_lottery_results[0]
: s->secret_lottery_results[l->rand_crypt->next() % s->secret_lottery_results.size()];
item.enforce_min_stack_size(limits);
item.enforce_stack_size_limits(limits);
item.id = l->generate_item_id(c->lobby_client_id);
p->add_item(item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
@@ -4904,7 +4950,7 @@ static asio::awaitable<void> on_quest_F95E_result_bb(shared_ptr<Client> c, Subco
} else if (item.data1[0] == 0x00) {
item.data1[4] |= 0x80; // Unidentified
} else {
item.enforce_min_stack_size(*s->item_stack_limits(c->version()));
item.enforce_stack_size_limits(*s->item_stack_limits(c->version()));
}
item.id = l->generate_item_id(0xFF);
@@ -4950,7 +4996,7 @@ static asio::awaitable<void> on_quest_F95F_result_bb(shared_ptr<Client> c, Subco
send_command_t(c, 0x60, 0x00, cmd_6xDB);
ItemData new_item = result.second;
new_item.enforce_min_stack_size(limits);
new_item.enforce_stack_size_limits(limits);
new_item.id = l->generate_item_id(c->lobby_client_id);
p->add_item(new_item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
@@ -5030,12 +5076,12 @@ static asio::awaitable<void> on_quest_F960_result_bb(shared_ptr<Client> c, Subco
p->add_item(item, *s->item_stack_limits(c->version()));
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (c->log.should_log(phosg::LogLevel::L_INFO)) {
string name = s->describe_item(c->version(), item, false);
string name = s->describe_item(c->version(), item);
c->log.info_f("Awarded item {}", name);
}
} catch (const out_of_range&) {
if (c->log.should_log(phosg::LogLevel::L_INFO)) {
string name = s->describe_item(c->version(), item, false);
string name = s->describe_item(c->version(), item);
c->log.info_f("Attempted to award item {}, but inventory was full", name);
}
}
@@ -5070,7 +5116,7 @@ static asio::awaitable<void> on_momoka_item_exchange_bb(shared_ptr<Client> c, Su
// TODO: We probably should use an allow-list here to prevent the client
// from creating arbitrary items if cheat mode is disabled.
ItemData new_item = cmd.replace_item;
new_item.enforce_min_stack_size(limits);
new_item.enforce_stack_size_limits(limits);
new_item.id = l->generate_item_id(c->lobby_client_id);
p->add_item(new_item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
@@ -5388,7 +5434,7 @@ const SubcommandDefinition subcommand_definitions[0x100] = {
/* 6xE1 */ {NONE, NONE, 0xE1, on_quest_F95F_result_bb},
/* 6xE2 */ {NONE, NONE, 0xE2, on_quest_F960_result_bb},
/* 6xE3 */ {NONE, NONE, 0xE3, on_invalid},
/* 6xE4 */ {NONE, NONE, 0xE4, on_invalid},
/* 6xE4 */ {NONE, NONE, 0xE4, on_incr_enemy_damage}, // Extended subcommand; see CommandFormats.hh
/* 6xE5 */ {NONE, NONE, 0xE5, on_invalid},
/* 6xE6 */ {NONE, NONE, 0xE6, on_invalid},
/* 6xE7 */ {NONE, NONE, 0xE7, on_invalid},
@@ -5415,7 +5461,7 @@ const SubcommandDefinition subcommand_definitions[0x100] = {
/* 6xFC */ {NONE, NONE, 0xFC, on_invalid},
/* 6xFD */ {NONE, NONE, 0xFD, on_invalid},
/* 6xFE */ {NONE, NONE, 0xFE, on_invalid},
/* 6xFF */ {NONE, NONE, 0xFF, on_invalid},
/* 6xFF */ {NONE, NONE, 0xFF, on_debug_info}, // Extended subcommand with no format; used for debugging patches
};
asio::awaitable<void> on_subcommand_multi(shared_ptr<Client> c, Channel::Message& msg) {
+1
View File
@@ -121,6 +121,7 @@ protected:
Version from_version,
bool from_client_customization);
G_6x70_Base_V1 base_v1(bool is_v3) const;
static uint32_t convert_game_flags(uint32_t game_flags, bool to_v3);
uint32_t get_game_flags(bool is_v3) const;
};
+22 -16
View File
@@ -218,16 +218,7 @@ bool PSOGCSnapshotFile::checksum_correct() const {
return (crc == this->checksum);
}
static uint32_t decode_rgb565(uint16_t c) {
// Input bits: rrrrrggg gggbbbbb
// Output bits: rrrrrrrr gggggggg bbbbbbbb aaaaaaaa
return ((c << 16) & 0xF8000000) | ((c << 11) & 0x07000000) | // R
((c << 13) & 0x00FC0000) | ((c << 7) & 0x00030000) | // G
((c << 11) & 0x0000F800) | ((c << 6) & 0x00000700) | // B
0x000000FF; // A
}
phosg::Image PSOGCSnapshotFile::decode_image() const {
phosg::ImageRGB888 PSOGCSnapshotFile::decode_image() const {
size_t width = this->width ? this->width.load() : 256;
size_t height = this->height ? this->height.load() : 192;
if (width != 256) {
@@ -238,14 +229,13 @@ phosg::Image PSOGCSnapshotFile::decode_image() const {
}
// 4x4 blocks of pixels
phosg::Image ret(width, height, false);
phosg::ImageRGB888 ret(width, height);
size_t offset = 0;
for (size_t y = 0; y < this->height; y += 4) {
for (size_t x = 0; x < this->width; x += 4) {
for (size_t yy = 0; yy < 4; yy++) {
for (size_t xx = 0; xx < 4; xx++) {
uint32_t color = decode_rgb565(this->pixels[offset++]);
ret.write_pixel(x + xx, y + yy, color);
ret.write(x + xx, y + yy, phosg::rgba8888_for_rgb565(this->pixels[offset++]));
}
}
}
@@ -312,6 +302,22 @@ PSOGCEp3CharacterFile::Character::operator PSOGCEp3NTECharacter() const {
return ret;
}
bool PSOXBFileHeader::checksum_correct() const {
uint32_t cs = phosg::crc32(&this->game_name, this->game_name.bytes());
cs = phosg::crc32(&this->file_name, this->file_name.bytes(), cs);
cs = phosg::crc32(&this->banner, this->banner.bytes(), cs);
cs = phosg::crc32(&this->icon, this->icon.bytes(), cs);
cs = phosg::crc32(&this->data_size, sizeof(this->data_size), cs);
cs = phosg::crc32("\0\0\0\0", 4, cs); // this->checksum (treated as zero)
return (cs == this->checksum);
}
void PSOXBFileHeader::check() const {
if (!this->checksum_correct()) {
throw runtime_error("Xbox file intermediate header checksum is incorrect");
}
}
void PSOBBGuildCardFile::Entry::clear() {
this->data.clear();
this->unknown_a1.clear(0);
@@ -830,7 +836,7 @@ shared_ptr<PSOBBCharacterFile> PSOBBCharacterFile::create_from_file(const PSOGCE
return ret;
}
shared_ptr<PSOBBCharacterFile> PSOBBCharacterFile::create_from_file(const PSOXBCharacterFileCharacter& src) {
shared_ptr<PSOBBCharacterFile> PSOBBCharacterFile::create_from_file(const PSOXBCharacterFile::Character& src) {
auto ret = PSOBBCharacterFile::create_from_config(
src.guild_card.guild_card_number,
src.inventory.language,
@@ -1101,10 +1107,10 @@ PSOBBCharacterFile::operator PSOGCCharacterFile::Character() const {
return ret;
}
PSOBBCharacterFile::operator PSOXBCharacterFileCharacter() const {
PSOBBCharacterFile::operator PSOXBCharacterFile::Character() const {
uint8_t language = this->inventory.language;
PSOXBCharacterFileCharacter ret;
PSOXBCharacterFile::Character ret;
ret.inventory = this->inventory;
ret.inventory.encode_for_client(Version::XB_V3, nullptr);
ret.disp = this->disp.to_dcpcv3<false>(language, language);
+124 -45
View File
@@ -91,6 +91,31 @@ struct PSOGCIFileHeader {
bool is_nte() const;
} __packed_ws__(PSOGCIFileHeader, 0x2088);
struct PSOXBFileHeader {
// The signature is computed by doing the following:
// // TODO: Should flags be 0 or 1? It looks like it should be 0 for
// // character files, but not sure about this
// auto handle = XCalculateSignatureBegin(flags);
// XCalculateSignatureUpdate(
// handle,
// &header.source_size,
// total_size - offsetof(PSOXBFileHeader, source_size));
// XCalculateSignatureEnd(handle, header.signature);
/* 0000 */ parray<uint8_t, 0x14> signature;
/* 0014 */ le_uint32_t source_size = 0; // == total file size - 0x4000
/* 0018 */ parray<uint8_t, 0x3FE8> unused; // Always blank (zeroes)
/* 4000 */ pstring<TextEncoding::MARKED, 0x20> game_name;
/* 4020 */ pstring<TextEncoding::MARKED, 0x20> file_name;
/* 4040 */ parray<uint8_t, 0x1800> banner; // Always blank (zeroes)
/* 5840 */ parray<uint8_t, 0x800> icon; // Always blank (zeroes)
/* 6040 */ le_uint32_t data_size = 0;
/* 6044 */ le_uint32_t checksum = 0; // Starts at game_name
/* 6048 */
bool checksum_correct() const;
void check() const;
} __packed_ws__(PSOXBFileHeader, 0x6048);
////////////////////////////////////////////////////////////////////////////////
// Subordinate structures
@@ -280,6 +305,35 @@ struct PSOGCEp3SystemFile {
/* 012C */
} __packed_ws__(PSOGCEp3SystemFile, 0x12C);
struct PSOXBSystemFile {
/* 0000 */ le_uint32_t checksum = 0;
/* 0004 */ le_int16_t music_volume = -50;
/* 0006 */ int8_t sound_volume = 0;
/* 0007 */ uint8_t language = 0;
/* 0008 */ be_int32_t server_time_delta_frames = 200;
/* 000C */ be_uint16_t udp_behavior = 0; // 0 = auto, 1 = on, 2 = off
/* 000E */ be_uint16_t surround_sound_enabled = 0;
/* 0010 */ parray<uint8_t, 0x0100> event_flags;
/* 0110 */ parray<uint8_t, 8> unknown_a1;
struct UserEntry {
/* 00 */ le_uint32_t xb_user_id_high = 0;
/* 04 */ le_uint32_t xb_user_id_low = 0;
/* 08 */ le_uint32_t unknown_a2;
/* 0C */ le_uint32_t last_write_year;
/* 10 */ le_uint32_t last_write_month;
/* 14 */ le_uint32_t last_write_day;
/* 18 */ le_uint32_t last_write_hour;
/* 1C */ le_uint32_t last_write_minute;
/* 20 */ le_uint32_t last_write_second;
/* 24 */ le_uint32_t flags = 1; // 1 = not present
/* 28 */ pstring<TextEncoding::ASCII, 0x10> gamertag;
/* 38 */
} __packed_ws__(UserEntry, 0x38);
/* 0118 */ parray<UserEntry, 4> users;
/* 01F8 */ le_uint32_t creation_timestamp = 0;
/* 01FC */
} __packed_ws__(PSOXBSystemFile, 0x1FC);
struct PSOBBMinimalSystemFile {
/* 0000 */ be_uint32_t checksum = 0;
/* 0004 */ be_int16_t music_volume = 0;
@@ -717,48 +771,65 @@ struct PSOGCEp3CharacterFile {
/* 194B0 */
} __packed_ws__(PSOGCEp3CharacterFile, 0x194B0);
struct PSOXBCharacterFileCharacter {
// This structure is internally split into two by the game. The offsets here
// are relative to the start of this structure (first column), and relative
// to the start of the second internal structure (second column).
// Most fields have the same meanings as in PSOGCCharacterFile::Character.
/* 0000:---- */ PlayerInventory inventory;
/* 034C:---- */ PlayerDispDataDCPCV3 disp;
/* 041C:0000 */ le_uint32_t validation_flags = 0;
/* 0420:0004 */ le_uint32_t creation_timestamp = 0;
/* 0424:0008 */ le_uint32_t signature = 0xC87ED5B1;
/* 0428:000C */ le_uint32_t play_time_seconds = 0;
/* 042C:0010 */ le_uint32_t option_flags = 0x00040058;
/* 0430:0014 */ le_uint32_t save_count = 1;
/* 0434:0018 */ pstring<TextEncoding::ASCII, 0x1C> ppp_username;
/* 0450:0034 */ pstring<TextEncoding::ASCII, 0x10> ppp_password;
/* 0460:0044 */ QuestFlags quest_flags;
/* 0660:0244 */ le_uint32_t death_count = 0;
/* 0664:0248 */ PlayerBank200 bank;
/* 192C:1510 */ GuildCardXB guild_card;
/* 1B58:173C */ parray<SaveFileSymbolChatEntryDCXB, 12> symbol_chats;
/* 1F78:1B5C */ parray<SaveFileShortcutEntryXB, 16> shortcuts;
/* 24B8:209C */ pstring<TextEncoding::MARKED, 0xAC> auto_reply;
/* 2518:20FC */ pstring<TextEncoding::MARKED, 0xAC> info_board;
// TODO: The following fields are guesses and have not been verified.
/* 2610:21F4 */ PlayerRecordsBattle battle_records;
/* 2628:220C */ parray<uint8_t, 4> unknown_a4;
/* 262C:2210 */ PlayerRecordsChallengeV3 challenge_records;
/* 272C:2310 */ parray<le_uint16_t, 20> tech_menu_shortcut_entries;
/* 2754:2338 */ ChoiceSearchConfig choice_search_config;
/* 276C:2350 */ parray<uint8_t, 0x10> unknown_a6;
/* 277C:2360 */ parray<le_uint32_t, 0x10> quest_counters;
/* 27BC:23A0 */ PlayerRecordsBattle offline_battle_records;
/* 27D4:23B8 */ parray<uint8_t, 4> unknown_a7;
struct UnknownA8Entry {
/* 00 */ le_uint32_t unknown_a1 = 0;
/* 04 */ parray<uint8_t, 0x1C> unknown_a2;
/* 20 */ parray<le_float, 4> unknown_a3;
/* 30 */
} __packed_ws__(UnknownA8Entry, 0x30);
/* 27D8:23BC */ parray<UnknownA8Entry, 5> unknown_a8;
/* 28C8:24AC */
} __packed_ws__(PSOXBCharacterFileCharacter, 0x28C8);
struct PSOXBCharacterFile {
struct Character {
// This structure is internally split into two by the game. The offsets here
// are relative to the start of this structure (first column), and relative
// to the start of the second internal structure (second column).
// Most fields have the same meanings as in PSOGCCharacterFile::Character.
/* 0000:---- */ PlayerInventory inventory;
/* 034C:---- */ PlayerDispDataDCPCV3 disp;
/* 041C:0000 */ le_uint32_t validation_flags = 0;
/* 0420:0004 */ le_uint32_t creation_timestamp = 0;
/* 0424:0008 */ le_uint32_t signature = 0xC87ED5B1;
/* 0428:000C */ le_uint32_t play_time_seconds = 0;
/* 042C:0010 */ le_uint32_t option_flags = 0x00040058;
/* 0430:0014 */ le_uint32_t save_count = 1;
/* 0434:0018 */ pstring<TextEncoding::ASCII, 0x1C> ppp_username;
/* 0450:0034 */ pstring<TextEncoding::ASCII, 0x10> ppp_password;
/* 0460:0044 */ QuestFlags quest_flags;
/* 0660:0244 */ le_uint32_t death_count = 0;
/* 0664:0248 */ PlayerBank200 bank;
/* 192C:1510 */ GuildCardXB guild_card;
/* 1B58:173C */ parray<SaveFileSymbolChatEntryDCXB, 12> symbol_chats;
/* 1F78:1B5C */ parray<SaveFileShortcutEntryXB, 16> shortcuts;
/* 24B8:209C */ pstring<TextEncoding::MARKED, 0xAC> auto_reply;
/* 2518:20FC */ pstring<TextEncoding::MARKED, 0xAC> info_board;
// TODO: The following fields are guesses and have not been verified.
/* 2610:21F4 */ PlayerRecordsBattle battle_records;
/* 2628:220C */ parray<uint8_t, 4> unknown_a4;
/* 262C:2210 */ PlayerRecordsChallengeV3 challenge_records;
/* 272C:2310 */ parray<le_uint16_t, 20> tech_menu_shortcut_entries;
/* 2754:2338 */ ChoiceSearchConfig choice_search_config;
/* 276C:2350 */ parray<uint8_t, 0x10> unknown_a6;
/* 277C:2360 */ parray<le_uint32_t, 0x10> quest_counters;
/* 27BC:23A0 */ PlayerRecordsBattle offline_battle_records;
/* 27D4:23B8 */ parray<uint8_t, 4> unknown_a7;
struct UnknownA8Entry {
/* 00 */ le_uint32_t unknown_a1 = 0;
/* 04 */ parray<uint8_t, 0x1C> unknown_a2;
/* 20 */ parray<le_float, 4> unknown_a3;
/* 30 */
} __packed_ws__(UnknownA8Entry, 0x30);
/* 27D8:23BC */ parray<UnknownA8Entry, 5> unknown_a8;
/* 28C8:24AC */
} __packed_ws__(Character, 0x28C8);
struct CharEntry {
Character character;
parray<uint8_t, 0x18> unknown_a1;
} __packed_ws__(CharEntry, 0x28E0);
/* 00000 */ le_uint32_t checksum = 0;
/* 00004 */ parray<CharEntry, 15> characters;
/* 26524 */ pstring<TextEncoding::ASCII, 0x10> serial_number;
/* 26534 */ pstring<TextEncoding::ASCII, 0x10> access_key;
/* 26544 */ pstring<TextEncoding::ASCII, 0x10> password;
/* 26554 */ be_uint64_t bgm_test_songs_unlocked = 0;
/* 2655C */ le_uint32_t save_count = 1;
/* 26560 */ le_uint32_t round2_seed = 0;
/* 26564 */
} __packed_ws__(PSOXBCharacterFile, 0x26564);
struct PSOBBCharacterFile {
// Most fields have the same meanings as in PSOGCCharacterFile::Character.
@@ -816,7 +887,7 @@ struct PSOBBCharacterFile {
static std::shared_ptr<PSOBBCharacterFile> create_from_file(const PSOGCNTECharacterFileCharacter& src);
static std::shared_ptr<PSOBBCharacterFile> create_from_file(const PSOGCCharacterFile::Character& src);
static std::shared_ptr<PSOBBCharacterFile> create_from_file(const PSOGCEp3CharacterFile::Character& src);
static std::shared_ptr<PSOBBCharacterFile> create_from_file(const PSOXBCharacterFileCharacter& src);
static std::shared_ptr<PSOBBCharacterFile> create_from_file(const PSOXBCharacterFile::Character& src);
PSODCNTECharacterFile::Character as_dc_nte(uint64_t hardware_id) const;
PSODC112000CharacterFile::Character as_11_2000(uint64_t hardware_id) const;
@@ -825,7 +896,7 @@ struct PSOBBCharacterFile {
operator PSOGCNTECharacterFileCharacter() const;
operator PSOGCCharacterFile::Character() const;
operator PSOGCEp3CharacterFile::Character() const;
operator PSOXBCharacterFileCharacter() const;
operator PSOXBCharacterFile::Character() const;
void add_item(const ItemData& item, const ItemData::StackLimits& limits);
ItemData remove_item(uint32_t item_id, uint32_t amount, const ItemData::StackLimits& limits);
@@ -947,6 +1018,14 @@ struct PSOGCGuildCardFile {
/* E28C */
} __packed_ws__(PSOGCGuildCardFile, 0xE28C);
struct PSOXBGuildCardFile {
/* 00000 */ le_uint32_t checksum = 0;
/* 00004 */ parray<GuildCardXB, 100> entries;
/* 0D934 */ parray<GuildCardXB, 0x1C> blocked_senders;
/* 11604 */ le_uint32_t creation_timestamp = 0;
/* 11608 */ le_uint32_t round2_seed = 0;
} __packed_ws__(PSOXBGuildCardFile, 0x1160C);
struct PSOBBGuildCardFile {
struct Entry {
/* 0000 */ GuildCardBB data;
@@ -987,7 +1066,7 @@ struct PSOGCSnapshotFile {
/* 1818C */
bool checksum_correct() const;
phosg::Image decode_image() const;
phosg::ImageRGB888 decode_image() const;
} __packed_ws__(PSOGCSnapshotFile, 0x1818C);
////////////////////////////////////////////////////////////////////////////////
+36 -10
View File
@@ -237,8 +237,6 @@ void send_server_init_bb(shared_ptr<Client> c, uint8_t flags) {
auto cmd = prepare_server_init_contents_bb(server_key, client_key, flags);
send_command_t(c, use_secondary_message ? 0x9B : 0x03, 0x00, cmd);
static const string primary_expected_first_data("\xB4\x00\x93\x00\x00\x00\x00\x00", 8);
static const string secondary_expected_first_data("\xDC\x00\xDB\x00\x00\x00\x00\x00", 8);
c->bb_detector_crypt = make_shared<PSOBBMultiKeyDetectorEncryption>(
c->require_server_state()->bb_private_keys,
bb_crypt_initial_client_commands,
@@ -452,10 +450,12 @@ asio::awaitable<C_ExecuteCodeResult_B3> send_function_call(
override_relocations_offset,
ignore_actually_runs_code_flag);
c->function_call_response_queue.emplace_back(promise);
c->enabled_flags |= code->client_flag;
co_return co_await promise->get();
}
asio::awaitable<void> send_function_call_multi(shared_ptr<Client> c, vector<shared_ptr<const CompiledFunctionCode>> codes) {
asio::awaitable<void> send_function_call_multi(
shared_ptr<Client> c, unordered_set<shared_ptr<const CompiledFunctionCode>> codes) {
if (codes.empty()) {
co_return;
}
@@ -468,6 +468,7 @@ asio::awaitable<void> send_function_call_multi(shared_ptr<Client> c, vector<shar
last_promise = make_shared<AsyncPromise<C_ExecuteCodeResult_B3>>();
c->function_call_response_queue.emplace_back(last_promise);
send_function_call(c->channel, c->enabled_flags, code);
c->enabled_flags |= code->client_flag;
}
if (c->channel->connected()) {
co_await last_promise->get();
@@ -498,7 +499,7 @@ void send_function_call(
code, label_writes, suffix_data, suffix_size, checksum_addr, checksum_size, override_relocations_offset,
Client::check_flag(client_enabled_flags, Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL));
ch->send(0xB2, code ? code->index : 0x00, data);
ch->send(0xB2, 0x00, data);
}
asio::awaitable<bool> send_protected_command(
@@ -647,7 +648,7 @@ void send_client_init_bb(shared_ptr<Client> c, uint32_t error_code) {
cmd.player_tag = 0x00010000;
cmd.guild_card_number = c->login->account->account_id;
cmd.security_token = team ? team->team_id : 0;
cmd.client_config.clear(0xFF);
cmd.client_config = c->bb_client_config;
cmd.can_create_team = 1;
cmd.episode_4_unlocked = 1;
@@ -1995,7 +1996,7 @@ void send_join_game(shared_ptr<Client> c, shared_ptr<Lobby> l) {
cmd.variations = l->variations;
cmd.client_id = c->lobby_client_id;
cmd.leader_id = l->leader_id;
cmd.disable_udp = 0x01; // Unused on PC/XB/BB
cmd.disable_udp = l->client_extension_flags();
cmd.difficulty = l->difficulty;
cmd.battle_mode = (l->mode == GameMode::BATTLE) ? 1 : 0;
cmd.event = l->event;
@@ -2030,7 +2031,7 @@ void send_join_game(shared_ptr<Client> c, shared_ptr<Lobby> l) {
S_JoinGame_DCNTE_64 cmd;
cmd.client_id = c->lobby_client_id;
cmd.leader_id = l->leader_id;
cmd.disable_udp = 0x01;
cmd.disable_udp = l->client_extension_flags();
cmd.variations = l->variations;
size_t player_count = populate_lobby_data(cmd);
send_command_t(c, 0x64, player_count, cmd);
@@ -2159,6 +2160,7 @@ void send_join_lobby_t(shared_ptr<Client> c, shared_ptr<Lobby> l, shared_ptr<Cli
S_JoinLobbyT<LobbyFlags, LobbyDataT, DispDataT> cmd;
cmd.lobby_flags.client_id = c->lobby_client_id;
cmd.lobby_flags.leader_id = l->leader_id;
cmd.lobby_flags.disable_udp = l->client_extension_flags();
cmd.lobby_flags.lobby_number = lobby_type;
cmd.lobby_flags.block_number = lobby_block;
cmd.lobby_flags.event = l->event;
@@ -2231,6 +2233,7 @@ void send_join_lobby_xb(shared_ptr<Client> c, shared_ptr<Lobby> l, shared_ptr<Cl
S_JoinLobby_XB_65_67_68 cmd;
cmd.lobby_flags.client_id = c->lobby_client_id;
cmd.lobby_flags.leader_id = l->leader_id;
cmd.lobby_flags.disable_udp = l->client_extension_flags();
cmd.lobby_flags.lobby_number = lobby_type;
cmd.lobby_flags.block_number = l->block;
cmd.lobby_flags.event = l->event;
@@ -2280,6 +2283,7 @@ void send_join_lobby_dc_nte(shared_ptr<Client> c, shared_ptr<Lobby> l,
S_JoinLobby_DCNTE_65_67_68 cmd;
cmd.lobby_flags.client_id = c->lobby_client_id;
cmd.lobby_flags.leader_id = l->leader_id;
cmd.lobby_flags.disable_udp = l->client_extension_flags();
vector<shared_ptr<Client>> lobby_clients;
if (joining_client) {
@@ -2402,7 +2406,7 @@ void send_update_lobby_data_bb(std::shared_ptr<Client> c) {
}
void send_player_leave_notification(shared_ptr<Lobby> l, uint8_t leaving_client_id) {
S_LeaveLobby_66_69_Ep3_E9 cmd = {leaving_client_id, l->leader_id, 1, 0};
S_LeaveLobby_66_69_Ep3_E9 cmd = {leaving_client_id, l->leader_id, l->client_extension_flags(), 0};
uint8_t cmd_num;
if (l->is_game()) {
cmd_num = l->check_flag(Lobby::Flag::IS_SPECTATOR_TEAM) ? 0xE9 : 0x66;
@@ -2593,6 +2597,29 @@ void send_player_stats_change(std::shared_ptr<Channel> ch, uint16_t client_id, P
send_command_vt(ch, (subs.size() > 0x400 / sizeof(G_UpdateEntityStat_6x9A)) ? 0x6C : 0x60, 0x00, subs);
}
void send_change_player_hp(std::shared_ptr<Channel> ch, uint16_t client_id, PlayerHPChange what, int16_t amount) {
uint8_t subcommand_number;
if (ch->version == Version::DC_NTE) {
subcommand_number = 0x2B;
} else if (ch->version == Version::DC_11_2000) {
subcommand_number = 0x2D;
} else {
subcommand_number = 0x2F;
}
G_ChangePlayerHP_6x2F cmd = {
{subcommand_number, sizeof(G_ChangePlayerHP_6x2F) / 4, client_id},
static_cast<uint32_t>(what), amount, client_id};
send_command_t(ch, 0x60, 0x00, cmd);
}
void send_change_player_hp(std::shared_ptr<Lobby> l, uint16_t client_id, PlayerHPChange what, int16_t amount) {
for (const auto& lc : l->clients) {
if (lc) {
send_change_player_hp(lc->channel, client_id, what, amount);
}
}
}
asio::awaitable<void> send_remove_negative_conditions(shared_ptr<Client> c) {
G_AddStatusEffect_6x0C cmd;
cmd.header = {0x0C, sizeof(G_AddStatusEffect_6x0C) >> 2, c->lobby_client_id};
@@ -2788,10 +2815,9 @@ void send_game_enemy_state(shared_ptr<Client> c) {
auto s = c->require_server_state();
vector<SyncEnemyStateEntry> entries;
bool is_v3 = !is_v1_or_v2(c->version());
for (auto ene_st : l->map_state->iter_enemy_states(c->version())) {
auto& entry = entries.emplace_back();
entry.flags = ene_st->get_game_flags(is_v3);
entry.flags = ene_st->game_flags;
entry.item_drop_id = (ene_st->server_flags & MapState::EnemyState::Flag::ITEM_DROPPED)
? 0xFFFF
: (0xCA0 + l->map_state->index_for_enemy_state(c->version(), ene_st));
+14 -6
View File
@@ -186,7 +186,7 @@ asio::awaitable<C_ExecuteCodeResult_B3> send_function_call(
bool ignore_actually_runs_code_flag = false);
asio::awaitable<void> send_function_call_multi(
std::shared_ptr<Client> c,
std::vector<std::shared_ptr<const CompiledFunctionCode>> codes);
std::unordered_set<std::shared_ptr<const CompiledFunctionCode>> codes);
asio::awaitable<bool> send_protected_command(std::shared_ptr<Client> c, const void* data, size_t size, bool echo_to_lobby);
asio::awaitable<void> send_dol_file(std::shared_ptr<Client> c, std::shared_ptr<DOLFileIndex::File> dol);
@@ -334,7 +334,7 @@ void send_arrow_update(std::shared_ptr<Lobby> l);
void send_unblock_join(std::shared_ptr<Client> c);
void send_resume_game(std::shared_ptr<Lobby> l, std::shared_ptr<Client> ready_client);
enum PlayerStatsChange {
enum class PlayerStatsChange {
SUBTRACT_HP = 0,
SUBTRACT_TP = 1,
SUBTRACT_MESETA = 2,
@@ -342,10 +342,18 @@ enum PlayerStatsChange {
ADD_TP = 4,
};
void send_player_stats_change(
std::shared_ptr<Client> c, PlayerStatsChange stat, uint32_t amount);
void send_player_stats_change(
std::shared_ptr<Channel> ch, uint16_t client_id, PlayerStatsChange stat, uint32_t amount);
void send_player_stats_change(std::shared_ptr<Client> c, PlayerStatsChange stat, uint32_t amount);
void send_player_stats_change(std::shared_ptr<Channel> ch, uint16_t client_id, PlayerStatsChange stat, uint32_t amount);
enum class PlayerHPChange {
SET_HP = 0,
INCREMENT_HP = 1,
MAXIMIZE_HP = 2,
};
void send_change_player_hp(std::shared_ptr<Channel> ch, uint16_t client_id, PlayerHPChange what, int16_t amount);
void send_change_player_hp(std::shared_ptr<Lobby> l, uint16_t client_id, PlayerHPChange what, int16_t amount);
asio::awaitable<void> send_remove_negative_conditions(std::shared_ptr<Client> c);
void send_remove_negative_conditions(std::shared_ptr<Channel> ch, uint16_t client_id);
void send_warp(std::shared_ptr<Channel> ch, uint8_t client_id, uint32_t floor, bool is_private);
+62 -42
View File
@@ -289,7 +289,7 @@ uint32_t ServerState::connect_address_for_client(shared_ptr<Client> c) const {
{
auto socket_channel = dynamic_pointer_cast<SocketChannel>(c->channel);
if (socket_channel) {
uint32_t addr = ipv4_addr_for_asio_addr(socket_channel->local_addr.address());
uint32_t addr = ipv4_addr_for_asio_addr(socket_channel->remote_addr.address());
uint32_t ret = is_local_address(addr) ? this->local_address : this->external_address;
return ret ? ret : addr;
}
@@ -400,23 +400,20 @@ shared_ptr<const QuestIndex> ServerState::quest_index(Version version) const {
}
size_t ServerState::default_min_level_for_game(Version version, Episode episode, uint8_t difficulty) const {
// A player's actual level is their displayed level - 1, so the minimums for
// Episode 1 (for example) are actually 1, 20, 40, 80.
const auto& min_levels = is_v4(version)
? this->min_levels_v4
: is_v3(version)
? this->min_levels_v3
: this->min_levels_v1_v2;
switch (episode) {
case Episode::EP1: {
const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[0] : DEFAULT_MIN_LEVELS_V3;
return min_levels.at(difficulty);
}
case Episode::EP2: {
const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[1] : DEFAULT_MIN_LEVELS_V3;
return min_levels.at(difficulty);
}
case Episode::EP1:
return min_levels[0].at(difficulty);
case Episode::EP2:
return min_levels[1].at(difficulty);
case Episode::EP3:
return 0;
case Episode::EP4: {
const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[2] : DEFAULT_MIN_LEVELS_V3;
return min_levels.at(difficulty);
}
case Episode::EP4:
return min_levels[2].at(difficulty);
default:
throw runtime_error("invalid episode");
}
@@ -501,13 +498,13 @@ shared_ptr<const ItemNameIndex> ServerState::item_name_index(Version version) co
return ret;
}
string ServerState::describe_item(Version version, const ItemData& item, bool include_color_codes) const {
string ServerState::describe_item(Version version, const ItemData& item, uint8_t flags) const {
if (is_v1(version)) {
ItemData encoded = item;
encoded.encode_for_version(version, this->item_parameter_table(version));
return this->item_name_index(version)->describe_item(encoded, include_color_codes);
return this->item_name_index(version)->describe_item(encoded, flags);
} else {
return this->item_name_index(version)->describe_item(item, include_color_codes);
return this->item_name_index(version)->describe_item(item, flags);
}
}
@@ -966,10 +963,10 @@ void ServerState::load_config_early() {
} else if (lower_path.ends_with(".gvm")) {
decompressed_gvm_data = phosg::load_file(path);
} else if (lower_path.ends_with(".bmp")) {
phosg::Image img(path);
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(path));
decompressed_gvm_data = encode_gvm(
img,
img.get_has_alpha() ? GVRDataFormat::RGB5A3 : GVRDataFormat::RGB565,
has_any_transparent_pixels(img) ? GVRDataFormat::RGB5A3 : GVRDataFormat::RGB565,
std::format("bnr{}", banner_index),
0x80 | banner_index);
banner_index++;
@@ -1059,7 +1056,11 @@ void ServerState::load_config_early() {
this->exp_share_multiplier = this->config_json->get_float("BBEXPShareMultiplier", 0.5);
this->server_global_drop_rate_multiplier = this->config_json->get_float("ServerGlobalDropRateMultiplier", 1);
set_log_levels_from_json(this->config_json->get("LogLevels", phosg::JSON::dict()));
if (this->is_debug) {
set_all_log_levels(phosg::LogLevel::L_DEBUG);
} else {
set_log_levels_from_json(this->config_json->get("LogLevels", phosg::JSON::dict()));
}
try {
this->run_shell_behavior = this->config_json->at("RunInteractiveShell").as_bool()
@@ -1095,6 +1096,7 @@ void ServerState::load_config_early() {
}
this->enable_chat_commands = this->config_json->get_bool("EnableChatCommands", true);
this->num_backup_character_slots = this->config_json->get_int("BackupCharacterSlots", 16);
this->version_name_colors.reset();
this->client_customization_name_color = 0;
@@ -1268,36 +1270,54 @@ void ServerState::load_config_early() {
this->rare_enemy_rates_challenge = MapState::DEFAULT_RARE_ENEMIES;
}
this->min_levels_v1_v2[0] = DEFAULT_MIN_LEVELS_V123;
this->min_levels_v1_v2[1] = DEFAULT_MIN_LEVELS_V123;
this->min_levels_v1_v2[2] = DEFAULT_MIN_LEVELS_V123;
this->min_levels_v3[0] = DEFAULT_MIN_LEVELS_V123;
this->min_levels_v3[1] = DEFAULT_MIN_LEVELS_V123;
this->min_levels_v3[2] = DEFAULT_MIN_LEVELS_V123;
this->min_levels_v4[0] = DEFAULT_MIN_LEVELS_V4_EP1;
this->min_levels_v4[1] = DEFAULT_MIN_LEVELS_V4_EP2;
this->min_levels_v4[2] = DEFAULT_MIN_LEVELS_V4_EP4;
try {
for (const auto& ep_it : this->config_json->get_dict("BBMinimumLevels")) {
array<size_t, 4> levels({0, 0, 0, 0});
for (size_t z = 0; z < 4; z++) {
levels[z] = ep_it.second->get_int(z) - 1;
}
switch (episode_for_token_name(ep_it.first)) {
case Episode::EP1:
this->min_levels_v4[0] = levels;
break;
case Episode::EP2:
this->min_levels_v4[1] = levels;
break;
case Episode::EP4:
this->min_levels_v4[2] = levels;
break;
default:
throw runtime_error("unknown episode");
auto populate_min_levels = [&](std::array<std::array<size_t, 4>, 3>& dest, const char* key_name) -> void {
try {
for (const auto& ep_it : this->config_json->get_dict(key_name)) {
array<size_t, 4> levels({0, 0, 0, 0});
for (size_t z = 0; z < 4; z++) {
levels[z] = ep_it.second->get_int(z) - 1;
}
switch (episode_for_token_name(ep_it.first)) {
case Episode::EP1:
dest[0] = levels;
break;
case Episode::EP2:
dest[1] = levels;
break;
case Episode::EP4:
dest[2] = levels;
break;
default:
throw runtime_error("unknown episode");
}
}
} catch (const out_of_range&) {
}
} catch (const out_of_range&) {
}
};
populate_min_levels(this->min_levels_v1_v2, "V1V2MinimumLevels");
populate_min_levels(this->min_levels_v3, "V3MinimumLevels");
populate_min_levels(this->min_levels_v4, "BBMinimumLevels");
this->bb_required_patches.clear();
try {
for (const auto& it : this->config_json->get_list("BBRequiredPatches")) {
this->bb_required_patches.emplace_back(it->as_string());
this->bb_required_patches.emplace(it->as_string());
}
} catch (const out_of_range&) {
}
this->auto_patches.clear();
try {
for (const auto& it : this->config_json->get_list("AutoPatches")) {
this->auto_patches.emplace(it->as_string());
}
} catch (const out_of_range&) {
}
+7 -2
View File
@@ -109,12 +109,14 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
uint64_t client_ping_interval_usecs = 30000000;
uint64_t client_idle_timeout_usecs = 60000000;
uint64_t patch_client_idle_timeout_usecs = 300000000;
bool is_debug = false;
bool ip_stack_debug = false;
bool allow_unregistered_users = false;
bool allow_pc_nte = false;
bool use_temp_accounts_for_prototypes = true;
std::array<uint16_t, NUM_VERSIONS> compatibility_groups = {};
bool enable_chat_commands = true;
size_t num_backup_character_slots = 16;
std::unique_ptr<std::array<uint32_t, NUM_NON_PATCH_VERSIONS>> version_name_colors;
uint32_t client_customization_name_color = 0x00000000;
uint8_t allowed_drop_modes_v1_v2_normal = 0x1F;
@@ -216,8 +218,11 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::shared_ptr<const SetDataTableBase> bb_solo_set_data_table_ep1_ult;
std::array<std::shared_ptr<const MapState::RareEnemyRates>, 4> rare_enemy_rates_by_difficulty;
std::shared_ptr<const MapState::RareEnemyRates> rare_enemy_rates_challenge;
std::array<std::array<size_t, 4>, 3> min_levels_v1_v2; // Indexed as [episode][difficulty]
std::array<std::array<size_t, 4>, 3> min_levels_v3; // Indexed as [episode][difficulty]
std::array<std::array<size_t, 4>, 3> min_levels_v4; // Indexed as [episode][difficulty]
std::vector<std::string> bb_required_patches;
std::unordered_set<std::string> bb_required_patches;
std::unordered_set<std::string> auto_patches;
CheatFlags cheat_flags;
struct QuestF960Result {
@@ -349,7 +354,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::shared_ptr<const ItemData::StackLimits> item_stack_limits(Version version) const;
std::shared_ptr<const ItemNameIndex> item_name_index_opt(Version version) const; // Returns null if missing
std::shared_ptr<const ItemNameIndex> item_name_index(Version version) const; // Throws if missing
std::string describe_item(Version version, const ItemData& item, bool include_color_codes) const;
std::string describe_item(Version version, const ItemData& item, uint8_t flags = 0) const;
ItemData parse_item_description(Version version, const std::string& description) const;
const std::vector<uint32_t>& public_lobby_search_order(Version version, bool is_client_customization) const;
+47 -24
View File
@@ -908,7 +908,11 @@ asio::awaitable<deque<string>> f_sc_ss(ShellCommand::Args& args) {
auto c = args.get_client();
if (args.command[1] == 's') {
co_await on_command_with_header(c, data);
if (c->proxy_session) {
send_command_with_header(c->proxy_session->server_channel, data.data(), data.size());
} else {
co_await on_command_with_header(c, data);
}
} else {
send_command_with_header(c->channel, data.data(), data.size());
}
@@ -947,23 +951,33 @@ ShellCommand c_show_slots(
});
asio::awaitable<deque<string>> fn_chat(ShellCommand::Args& args) {
auto c = args.get_proxy_client();
auto c = args.get_client();
bool is_dchat = (args.command == "dchat");
if (!is_dchat && uses_utf16(c->version())) {
send_chat_message_from_client(c->proxy_session->server_channel, args.args, 0);
} else {
string data(8, '\0');
data.push_back('\x09');
data.push_back('E');
if (is_dchat) {
data += phosg::parse_data_string(args.args, nullptr, phosg::ParseDataFlags::ALLOW_FILES);
if (c->proxy_session) {
if (!is_dchat && uses_utf16(c->version())) {
send_chat_message_from_client(c->proxy_session->server_channel, args.args, 0);
} else {
data += args.args;
data.push_back('\0');
string data(8, '\0');
data.push_back('\x09');
data.push_back('E');
if (is_dchat) {
data += phosg::parse_data_string(args.args, nullptr, phosg::ParseDataFlags::ALLOW_FILES);
} else {
data += args.args;
data.push_back('\0');
}
data.resize((data.size() + 3) & (~3));
c->proxy_session->server_channel->send(0x06, 0x00, data);
}
} else if (c->login) {
string text = is_dchat ? phosg::parse_data_string(args.args, nullptr, phosg::ParseDataFlags::ALLOW_FILES) : args.args;
auto l = c->require_lobby();
for (auto& lc : l->clients) {
if (lc) {
send_chat_message(lc, c->login->account->account_id, c->character()->disp.name.decode(c->language()), text, 0);
}
}
data.resize((data.size() + 3) & (~3));
c->proxy_session->server_channel->send(0x06, 0x00, data);
}
co_return deque<string>{};
@@ -977,18 +991,27 @@ ShellCommand c_dchat("dchat", "dchat DATA\n\
fn_chat);
asio::awaitable<deque<string>> fn_wchat(ShellCommand::Args& args) {
auto c = args.get_proxy_client();
auto c = args.get_client();
if (!is_ep3(c->version())) {
throw runtime_error("wchat can only be used on Episode 3");
}
string data(8, '\0');
data.push_back('\x40'); // private_flags: visible to all
data.push_back('\x09');
data.push_back('E');
data += args.args;
data.push_back('\0');
data.resize((data.size() + 3) & (~3));
c->proxy_session->server_channel->send(0x06, 0x00, data);
if (c->proxy_session) {
string data(8, '\0');
data.push_back('\x40'); // private_flags: visible to all
data.push_back('\x09');
data.push_back('E');
data += args.args;
data.push_back('\0');
data.resize((data.size() + 3) & (~3));
c->proxy_session->server_channel->send(0x06, 0x00, data);
} else if (c->login) {
auto l = c->require_lobby();
for (auto& lc : l->clients) {
if (lc) {
send_chat_message(lc, c->login->account->account_id, c->character()->disp.name.decode(c->language()), args.args, 0x40);
}
}
}
co_return deque<string>{};
}
ShellCommand c_wc("wc", "wc TEXT", fn_wchat);
@@ -1068,7 +1091,7 @@ ShellCommand c_create_item(
send_drop_stacked_item_to_channel(args.s, c->channel, item, c->floor, c->pos);
send_drop_stacked_item_to_channel(args.s, c->proxy_session->server_channel, item, c->floor, c->pos);
string name = args.s->describe_item(c->version(), item, true);
string name = args.s->describe_item(c->version(), item, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
send_text_message(c->channel, "$C7Item created:\n" + name);
co_return deque<string>{};
});
+1 -1
View File
@@ -805,7 +805,7 @@ char char_for_challenge_rank(uint8_t rank) {
return "BAS"[rank];
}
const array<size_t, 4> DEFAULT_MIN_LEVELS_V3({0, 19, 39, 79});
const array<size_t, 4> DEFAULT_MIN_LEVELS_V123({0, 19, 39, 79});
const array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP1({0, 19, 39, 79});
const array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP2({0, 29, 49, 89});
const array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP4({0, 39, 79, 109});
+1 -1
View File
@@ -106,7 +106,7 @@ uint32_t class_flags_for_class(uint8_t char_class);
char char_for_challenge_rank(uint8_t rank);
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V3;
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V123;
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP1;
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP2;
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP4;
+5 -5
View File
@@ -98,14 +98,14 @@ void TeamIndex::Team::save_config() const {
}
void TeamIndex::Team::load_flag() {
phosg::Image img(this->flag_filename());
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(this->flag_filename()));
if (img.get_width() != 32 || img.get_height() != 32) {
throw runtime_error("incorrect flag image dimensions");
}
this->flag_data.reset(new parray<le_uint16_t, 0x20 * 0x20>());
for (size_t y = 0; y < 32; y++) {
for (size_t x = 0; x < 32; x++) {
this->flag_data->at(y * 0x20 + x) = encode_rgba8888_to_argb1555(img.read_pixel(x, y));
this->flag_data->at(y * 0x20 + x) = phosg::argb1555_for_rgba8888(img.read(x, y));
}
}
}
@@ -114,13 +114,13 @@ void TeamIndex::Team::save_flag() const {
if (!this->flag_data) {
return;
}
phosg::Image img(32, 32, true);
phosg::ImageRGBA8888N img(32, 32);
for (size_t y = 0; y < 32; y++) {
for (size_t x = 0; x < 32; x++) {
img.write_pixel(x, y, decode_argb1555_to_rgba8888(this->flag_data->at(y * 0x20 + x)));
img.write(x, y, phosg::rgba8888_for_argb1555(this->flag_data->at(y * 0x20 + x)));
}
}
img.save(this->flag_filename(), phosg::Image::Format::WINDOWS_BITMAP);
phosg::save_file(this->flag_filename(), img.serialize(phosg::ImageFormat::WINDOWS_BITMAP));
}
void TeamIndex::Team::delete_files() const {
+17 -28
View File
@@ -215,51 +215,40 @@ bool specific_version_is_indeterminate(uint32_t specific_version) {
}
bool specific_version_is_dc(uint32_t specific_version) {
// All v1 and v2 specific_versions are DC except 324F4A57 (2OJW), which is PC
// All v1 and v2 specific_versions are DC except 2OJW and 2OJZ, which are PC
uint8_t major_version = specific_version >> 24;
if (major_version < 0x31 || major_version > 0x32) {
return false;
}
return (specific_version != SPECIFIC_VERSION_PC_V2_DEFAULT);
return !specific_version_is_pc_v2(specific_version);
}
bool specific_version_is_pc_v2(uint32_t specific_version) {
return (specific_version == SPECIFIC_VERSION_PC_V2_DEFAULT);
return ((specific_version == SPECIFIC_VERSION_PC_V2_DEFAULT) || (specific_version == SPECIFIC_VERSION_PC_V2_FINAL));
}
bool specific_version_is_gc(uint32_t specific_version) {
// GC specific_versions are 3GRV, where G is [OS], R is [JEP], V is [0-9T]
if ((specific_version & 0xFF000000) != 0x33000000) {
return false;
}
char game = specific_version >> 16;
if ((game != 'O') && (game != 'S')) {
return false;
}
char region = specific_version >> 8;
if ((region != 'J') && (region != 'E') && (region != 'P')) {
return false;
}
char revision = specific_version;
return (isdigit(revision) || (revision == 'T'));
// GC specific_versions are 3___
return ((specific_version & 0xFF000000) == 0x33000000);
}
bool specific_version_is_xb(uint32_t specific_version) {
// XB specific_versions are 4ORV, where R is [JEP], V is [BDU]
if ((specific_version & 0xFFFF0000) != 0x344F0000) {
return false;
}
char region = specific_version >> 8;
if ((region != 'J') && (region != 'E') && (region != 'P')) {
return false;
}
char revision = specific_version;
return ((revision == 'B') || (revision == 'D') || (revision == 'U'));
// XB specific_versions are 4O__
return ((specific_version & 0xFF000000) == 0x34000000);
}
bool specific_version_is_bb(uint32_t specific_version) {
// BB specific_versions are 5XXX, where X is an encoding of the revision number
return (specific_version & 0xFF000000) == 0x35000000;
return ((specific_version & 0xFF000000) == 0x35000000);
}
string str_for_specific_version(uint32_t specific_version) {
string ret;
for (size_t z = 0; z < 4; z++) {
char ch = specific_version >> (24 - (z << 3));
ret.push_back(isalnum(ch) ? ch : '_');
}
return ret;
}
const char* file_path_token_for_version(Version version) {
+4 -1
View File
@@ -191,8 +191,9 @@ constexpr uint32_t SPECIFIC_VERSION_DC_V1_US = 0x314F4546; // 1OEF
constexpr uint32_t SPECIFIC_VERSION_DC_V1_EU_INDETERMINATE = 0x314F5000; // 1OP_
constexpr uint32_t SPECIFIC_VERSION_DC_V1_INDETERMINATE = 0x31000000; // 1___
constexpr uint32_t SPECIFIC_VERSION_DC_V2_INDETERMINATE = 0x32000000; // 2___
constexpr uint32_t SPECIFIC_VERSION_PC_V2_INDETERMINATE = 0x324F4A00; // 2OJW
constexpr uint32_t SPECIFIC_VERSION_PC_V2_INDETERMINATE = 0x324F4A00; // 2OJ_
constexpr uint32_t SPECIFIC_VERSION_PC_V2_DEFAULT = 0x324F4A57; // 2OJW
constexpr uint32_t SPECIFIC_VERSION_PC_V2_FINAL = 0x324F4A5A; // 2OJZ
constexpr uint32_t SPECIFIC_VERSION_GC_NTE = 0x334F4A54; // 3OJT
constexpr uint32_t SPECIFIC_VERSION_GC_V3_EU = 0x334F5030; // 3OP0
constexpr uint32_t SPECIFIC_VERSION_GC_V3_US_12 = 0x334F4532; // 3OE2
@@ -218,6 +219,8 @@ bool specific_version_is_gc(uint32_t specific_version);
bool specific_version_is_xb(uint32_t specific_version);
bool specific_version_is_bb(uint32_t specific_version);
std::string str_for_specific_version(uint32_t specific_version);
enum class ServerBehavior {
PC_CONSOLE_DETECT = 0,
GAME_SERVER,
@@ -0,0 +1,42 @@
.meta name="Kill count fix"
.meta description="Fixes client-side\nkill counts when\nmultiple enemies are\nkilled on the same\nframe"
.meta hide_from_patches_menu
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
.data <VERS 0x8012D2D4 0x8012D518 0x8012D550 0x8012D4B0 0x8012D578 0x8012D578 0x8012D4C0 0x8012D698>
.deltaof TItemWeapon_SealedJSword_count_kill, TItemWeapon_SealedJSword_count_kill_end
.address <VERS 0x8012D2D4 0x8012D518 0x8012D550 0x8012D4B0 0x8012D578 0x8012D578 0x8012D4C0 0x8012D698>
TItemWeapon_SealedJSword_count_kill: # [std] (TItemWeapon_SealedJSword* this @ r3) -> void
lwz r4, [r3 + 0xF0] # r4 = this->owner_player
lha r5, [r4 + 0x11A] # r5 = this->owner_player->num_kills_since_map_load
lha r6, [r3 + 0x1F8] # r6 = this->last_owner_player_kill_count
lhz r7, [r3 + 0xE8] # r7 = this->kill_count
cmp r6, r5
bge TItemWeapon_SealedJSword_count_kill_skip_update
lwz r8, [r3 + 0xDC]
andi. r8, r8, 0x100
beq TItemWeapon_SealedJSword_count_kill_skip_incr # if (!(flags & 0x100)) don't incr kill count
sub r8, r5, r6
add r7, r7, r8
sth [r3 + 0xE8], r7
TItemWeapon_SealedJSword_count_kill_skip_incr:
sth [r3 + 0x1F8], r5
TItemWeapon_SealedJSword_count_kill_skip_update:
cmplwi r7, 23000
blt TItemWeapon_SealedJSword_count_kill_skip_set_flag
lwz r8, [r3 + 0xDC]
ori r8, r8, 0x200
stw [r3 + 0xDC], r8
TItemWeapon_SealedJSword_count_kill_skip_set_flag:
blr
TItemWeapon_SealedJSword_count_kill_end:
.data 0x00000000
.data 0x00000000
@@ -0,0 +1,36 @@
.meta name="Kill count fix"
.meta description="Fixes client-side\nkill counts when\nmultiple enemies are\nkilled on the same\nframe"
.meta hide_from_patches_menu
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksXB
.data <VERS 0x00197610 0x001977A0 0x00197920 0x00197880 0x00197810 0x001978A0 0x00197840>
.deltaof TItemWeapon_SealedJSword_count_kill, TItemWeapon_SealedJSword_count_kill_end
.address <VERS 0x00197610 0x001977A0 0x00197920 0x00197880 0x00197810 0x001978A0 0x00197840>
TItemWeapon_SealedJSword_count_kill:
mov eax, [ecx + 0xF0]
movsx eax, word [eax + 0x11A]
movsx edx, word [ecx + 0x1F8]
sub edx, eax
jge TItemWeapon_SealedJSword_count_kill_skip_update
test dword [ecx + 0xDC], 0x100
jz TItemWeapon_SealedJSword_count_kill_skip_incr
sub [ecx + 0xE8], dx
TItemWeapon_SealedJSword_count_kill_skip_incr:
mov [ecx + 0x1F8], ax
TItemWeapon_SealedJSword_count_kill_skip_update:
cmp word [ecx + 0xE8], 23000
jb TItemWeapon_SealedJSword_count_kill_skip_set_flag
or dword [ecx + 0xDC], 0x200
TItemWeapon_SealedJSword_count_kill_skip_set_flag:
ret
TItemWeapon_SealedJSword_count_kill_end:
.data 0x00000000
.data 0x00000000
@@ -0,0 +1,86 @@
.meta name="Kill count fix"
.meta description="Fixes client-side\nkill counts when\nmultiple enemies are\nkilled on the same\nframe"
.meta hide_from_patches_menu
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksBB
.data 0x005E32C8
.deltaof TItemUnitUnsealable_count_kill, TItemUnitUnsealable_count_kill_end
.address 0x005E32C8
TItemUnitUnsealable_count_kill: # [std] (TItemUnitUnsealable* this @ ecx) -> void
mov eax, [ecx + 0xF8]
movsx eax, word [eax + 0x11A] # eax = this->owner_player->num_kills_since_map_load
movsx edx, word [ecx + 0x1E4] # edx = this->last_owner_player_kill_count
sub edx, eax # edx = this->last_owner_player_kill_count - this->owner_player->num_kills_since_map_load (edx should be 0 or negative)
jge TItemUnitUnsealable_count_kill_skip_update
test dword [ecx + 0xDC], 0x100
jz TItemUnitUnsealable_count_kill_skip_incr # if (!(this->flags & 0x100)) don't incr kill count
sub [ecx + 0xE8], dx # this->kill_count -= edx
TItemUnitUnsealable_count_kill_skip_incr:
mov [ecx + 0x1E4], ax # this->last_owner_player_kill_count = this->owner_player->num_kills_since_map_load
TItemUnitUnsealable_count_kill_skip_update:
cmp word [ecx + 0xE8], 20000
jb TItemUnitUnsealable_count_kill_skip_set_flag
or dword [ecx + 0xDC], 0x200
TItemUnitUnsealable_count_kill_skip_set_flag:
jmp 0x005E2C34
TItemUnitUnsealable_count_kill_end:
.data 0x005F3EFC
.deltaof TItemWeapon_LameDArgent_count_kill, TItemWeapon_LameDArgent_count_kill_end
.address 0x005F3EFC
TItemWeapon_LameDArgent_count_kill:
mov eax, [ecx + 0xF8]
movsx eax, word [eax + 0x11A]
movsx edx, word [ecx + 0x240]
sub edx, eax
jge TItemWeapon_LameDArgent_count_kill_skip_update
test dword [ecx + 0xDC], 0x100
jz TItemWeapon_LameDArgent_count_kill_skip_incr
sub [ecx + 0xE8], dx
TItemWeapon_LameDArgent_count_kill_skip_incr:
mov [ecx + 0x240], ax
TItemWeapon_LameDArgent_count_kill_skip_update:
cmp word [ecx + 0xE8], 10000
jb TItemWeapon_LameDArgent_count_kill_skip_set_flag
or dword [ecx + 0xDC], 0x200
TItemWeapon_LameDArgent_count_kill_skip_set_flag:
ret
TItemWeapon_LameDArgent_count_kill_end:
.data 0x005FCA74
.deltaof TItemWeapon_SealedJSword_count_kill, TItemWeapon_SealedJSword_count_kill_end
.address 0x005FCA74
TItemWeapon_SealedJSword_count_kill:
mov eax, [ecx + 0xF8]
movsx eax, word [eax + 0x11A]
movsx edx, word [ecx + 0x240]
sub edx, eax
jge TItemWeapon_SealedJSword_count_kill_skip_update
test dword [ecx + 0xDC], 0x100
jz TItemWeapon_SealedJSword_count_kill_skip_incr
sub [ecx + 0xE8], dx
TItemWeapon_SealedJSword_count_kill_skip_incr:
mov [ecx + 0x240], ax
TItemWeapon_SealedJSword_count_kill_skip_update:
cmp word [ecx + 0xE8], 23000
jb TItemWeapon_SealedJSword_count_kill_skip_set_flag
or dword [ecx + 0xDC], 0x200
TItemWeapon_SealedJSword_count_kill_skip_set_flag:
ret
TItemWeapon_SealedJSword_count_kill_end:
.data 0x00000000
.data 0x00000000
@@ -1,32 +0,0 @@
# This patch disables the logic that causes all unlockable areas to be open by
# default for all players, instead restoring the logic that checks quest flags
# to open areas (as previous PSO versions used).
# This patch is intended to be used in the BBRequiredPatches field in
# config.json if you want the classic behavior, hence the presence of the
# hide_from_patches_menu directive here.
.meta name="Classic main warp behavior"
.meta description=""
.meta hide_from_patches_menu
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksBB
.data 0x0064A5DE # Episode 1
.data 1
.binary 01
.data 0x0064A448 # Episode 2
.data 2
.binary 0100
.data 0x0064A529 # Episode 4
.data 1
.binary 01
.data 0x0064A658 # Non-Normal difficulty check
.data 2
nop
nop
.data 0
.data 0
@@ -10,21 +10,23 @@
.meta description=""
.meta hide_from_patches_menu
.versions 59NJ 59NL
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksBB
.data 0x0064A642 # Episode 1
.data <VERS 0x0064A642 0x0064A5DE> # Episode 1
.data 1
.binary 01
.data 0x0064A4AC # Episode 2
.data <VERS 0x0064A4AC 0x0064A448> # Episode 2
.data 2
.binary 0100
.data 0x0064A58D # Episode 4
.data <VERS 0x0064A58D 0x0064A529> # Episode 4
.data 1
.binary 01
.data 0x0064A6BC # Non-Normal difficulty check
.data <VERS 0x0064A6BC 0x0064A658> # Non-Normal difficulty check
.data 2
nop
nop
@@ -1,26 +0,0 @@
# It would be a bad idea to remove `.meta hide_from_patches_menu` to make this
# patch an option for players to be able to select; either all players on the
# server should have this patch, or none should have it.
# This patch clears the list of unreleased items on the client, so the client
# never creates buggy items when the server generates an item that wasn't
# released on the official servers.
.meta name="Clear unreleased item list"
.meta description=""
.meta hide_from_patches_menu
entry_ptr:
reloc0:
.offsetof start
start:
xor eax, eax
mov edx, esp
mov esp, 0x009F81B0
mov ecx, 0x3C
again:
push 0
dec ecx
jnz again
mov esp, edx
ret
@@ -10,13 +10,15 @@
.meta description=""
.meta hide_from_patches_menu
.versions 59NJ 59NL
entry_ptr:
reloc0:
.offsetof start
start:
xor eax, eax
mov edx, esp
mov esp, 0x009F61B0
mov esp, <VERS 0x009F61B0 0x009F81B0>
mov ecx, 0x3C
again:
push 0
@@ -67,8 +67,6 @@ enable_scroll_start:
mov ecx, [eax + 0xEC] # ecx = scroll_bar->client_id
imul ecx, ecx, 0x24
# Set up scroll bar graphics (in struct at scroll_bar + 0x1C)
# TODO: Even though we set this up the same way PSO Xbox does, it still
# doesn't render. Figure this out and fix it.
mov dword [eax + ecx + 0x1C], 0x439D0000
mov dword [eax + ecx + 0x20], 0x43360000
mov dword [eax + ecx + 0x24], 0x439D0000
@@ -77,7 +75,7 @@ enable_scroll_start:
mov dword [eax + ecx + 0x30], 0x425EA3D7
mov dword [eax + ecx + 0x34], 0x00000008
mov dword [eax + ecx + 0x38], 0x00000000
mov dword [eax + ecx + 0x2C], 0x00000000
mov dword [eax + ecx + 0x3C], 0x00000000
or dword [eax + 0xF0], 1 # scroll_bar->flags |= 1
mov ecx, [eax + 0xEC]
shl ecx, 4
@@ -119,7 +117,7 @@ fix_scroll_patch1_end:
apply_fix_scroll_patch2:
# This patch changes the TAdSinglePlyChrSelectGC::selected_index_within_view
# to be the selected character's absolute index (including scroll_offset),
# not the index only within to the displayed four characters
# not the index only within the displayed four characters
push 6 # Call size
push 0x00413CD8 # Call address
call get_code_size_for_fix_scroll_patch2
@@ -166,7 +164,7 @@ selection_index_fix2_end:
apply_preview_window_fix:
# This patch fixes the preview display so it will show the correct section
# ID, etc.
# ID, level, etc.
push 5 # Call size
push 0x0040216C # Call address
call get_code_size_for_preview_window_fix
@@ -528,14 +526,14 @@ show_slot_number_strend_done:
lea ecx, [ecx + ebp + 1]
push ecx # Slot number (scroll_offset + z)
call get_show_slot_number_suffix_fmt
.binary 2000280023002500640029000000 # L" (#%d)"
.binary 20002800230025006400290020000000 # L" (#%d) "
get_show_slot_number_suffix_fmt:
push eax # Destination buffer
mov eax, 0x00857E29 # _swprintf
call eax
add esp, 0x0C
jmp show_slot_number_end
.zero 0x98
.zero 0x96
show_slot_number_end: # 00401E4D
# End static patches
@@ -1,564 +0,0 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
# region @ 8000B088 (88 bytes)
.data 0x8000B088 # address
.data 0x00000058 # size
.data 0x7FA3EB78 # 8000B088 => mr r3, r29
.data 0x38800000 # 8000B08C => li r4, 0x0000
.data 0x481AEB11 # 8000B090 => bl +0x001AEB10 /* 801B9BA0 */
.data 0x7FA3EB78 # 8000B094 => mr r3, r29
.data 0x481AEDE0 # 8000B098 => b +0x001AEDE0 /* 801B9E78 */
.data 0x881F0000 # 8000B09C => lbz r0, [r31]
.data 0x28090001 # 8000B0A0 => cmplwi r9, 1
.data 0x4082000C # 8000B0A4 => bne +0x0000000C /* 8000B0B0 */
.data 0x881F0001 # 8000B0A8 => lbz r0, [r31 + 0x0001]
.data 0x3BFF0002 # 8000B0AC => addi r31, r31, 0x0002
.data 0x48100B68 # 8000B0B0 => b +0x00100B68 /* 8010BC18 */
.data 0x39200000 # 8000B0B4 => li r9, 0x0000
.data 0x48100AF9 # 8000B0B8 => bl +0x00100AF8 /* 8010BBB0 */
.data 0x7F43D378 # 8000B0BC => mr r3, r26
.data 0x7F64DB78 # 8000B0C0 => mr r4, r27
.data 0x7F85E378 # 8000B0C4 => mr r5, r28
.data 0x7FA6EB78 # 8000B0C8 => mr r6, r29
.data 0x7FC7F378 # 8000B0CC => mr r7, r30
.data 0x7FE8FB78 # 8000B0D0 => mr r8, r31
.data 0x39200001 # 8000B0D4 => li r9, 0x0001
.data 0x48100AD9 # 8000B0D8 => bl +0x00100AD8 /* 8010BBB0 */
.data 0x48102F64 # 8000B0DC => b +0x00102F64 /* 8010E040 */
# region @ 8000B5C8 (20 bytes)
.data 0x8000B5C8 # address
.data 0x00000014 # size
.data 0x80630098 # 8000B5C8 => lwz r3, [r3 + 0x0098]
.data 0x483D5999 # 8000B5CC => bl +0x003D5998 /* 803E0F64 */
.data 0x807F042C # 8000B5D0 => lwz r3, [r31 + 0x042C]
.data 0x809F0430 # 8000B5D4 => lwz r4, [r31 + 0x0430]
.data 0x48178C7C # 8000B5D8 => b +0x00178C7C /* 80184254 */
# region @ 8000BBD0 (32 bytes)
.data 0x8000BBD0 # address
.data 0x00000020 # size
.data 0x809F0370 # 8000BBD0 => lwz r4, [r31 + 0x0370]
.data 0x3884FC00 # 8000BBD4 => subi r4, r4, 0x0400
.data 0x909F0370 # 8000BBD8 => stw [r31 + 0x0370], r4
.data 0x807F0014 # 8000BBDC => lwz r3, [r31 + 0x0014]
.data 0x28030000 # 8000BBE0 => cmplwi r3, 0
.data 0x41820008 # 8000BBE4 => beq +0x00000008 /* 8000BBEC */
.data 0x90830060 # 8000BBE8 => stw [r3 + 0x0060], r4
.data 0x48165428 # 8000BBEC => b +0x00165428 /* 80171014 */
# region @ 8000C3F8 (124 bytes)
.data 0x8000C3F8 # address
.data 0x0000007C # size
.data 0x28040000 # 8000C3F8 => cmplwi r4, 0
.data 0x4D820020 # 8000C3FC => beqlr
.data 0x9421FFF0 # 8000C400 => stwu [r1 - 0x0010], r1
.data 0x481AD7A0 # 8000C404 => b +0x001AD7A0 /* 801B9BA4 */
.data 0x9421FFE0 # 8000C408 => stwu [r1 - 0x0020], r1
.data 0x7C0802A6 # 8000C40C => mflr r0
.data 0x90010024 # 8000C410 => stw [r1 + 0x0024], r0
.data 0xBF410008 # 8000C414 => stmw [r1 + 0x0008], r26
.data 0x7C7F1B78 # 8000C418 => mr r31, r3
.data 0x4BFFFFDD # 8000C41C => bl -0x00000024 /* 8000C3F8 */
.data 0x3BC00000 # 8000C420 => li r30, 0x0000
.data 0x3BBF0D04 # 8000C424 => addi r29, r31, 0x0D04
.data 0x837F032C # 8000C428 => lwz r27, [r31 + 0x032C]
.data 0x839D0000 # 8000C42C => lwz r28, [r29]
.data 0x7F83E379 # 8000C430 => mr. r3, r28
.data 0x41820018 # 8000C434 => beq +0x00000018 /* 8000C44C */
.data 0x38800001 # 8000C438 => li r4, 0x0001
.data 0x480FED81 # 8000C43C => bl +0x000FED80 /* 8010B1BC */
.data 0x7F83E378 # 8000C440 => mr r3, r28
.data 0x38800001 # 8000C444 => li r4, 0x0001
.data 0x480FEEF1 # 8000C448 => bl +0x000FEEF0 /* 8010B338 */
.data 0x3BBD0004 # 8000C44C => addi r29, r29, 0x0004
.data 0x3BDE0001 # 8000C450 => addi r30, r30, 0x0001
.data 0x2C1E000D # 8000C454 => cmpwi r30, 13
.data 0x4180FFD4 # 8000C458 => blt -0x0000002C /* 8000C42C */
.data 0x937F032C # 8000C45C => stw [r31 + 0x032C], r27
.data 0xBB410008 # 8000C460 => lmw r26, [r1 + 0x0008]
.data 0x80010024 # 8000C464 => lwz r0, [r1 + 0x0024]
.data 0x7C0803A6 # 8000C468 => mtlr r0
.data 0x38210020 # 8000C46C => addi r1, r1, 0x0020
.data 0x4E800020 # 8000C470 => blr
# region @ 8000C640 (20 bytes)
.data 0x8000C640 # address
.data 0x00000014 # size
.data 0x54800673 # 8000C640 => rlwinm. r0, r4, 0, 25, 25
.data 0x41820008 # 8000C644 => beq +0x00000008 /* 8000C64C */
.data 0x38800000 # 8000C648 => li r4, 0x0000
.data 0x38040009 # 8000C64C => addi r0, r4, 0x0009
.data 0x4810C938 # 8000C650 => b +0x0010C938 /* 80118F88 */
# region @ 8000C6D0 (32 bytes)
.data 0x8000C6D0 # address
.data 0x00000020 # size
.data 0x38000001 # 8000C6D0 => li r0, 0x0001
.data 0x901D0054 # 8000C6D4 => stw [r29 + 0x0054], r0
.data 0x807D0024 # 8000C6D8 => lwz r3, [r29 + 0x0024]
.data 0x48211244 # 8000C6DC => b +0x00211244 /* 8021D920 */
.data 0x38000001 # 8000C6E0 => li r0, 0x0001
.data 0x901F0378 # 8000C6E4 => stw [r31 + 0x0378], r0
.data 0x807F0024 # 8000C6E8 => lwz r3, [r31 + 0x0024]
.data 0x482146F4 # 8000C6EC => b +0x002146F4 /* 80220DE0 */
# region @ 8000C8A0 (20 bytes)
.data 0x8000C8A0 # address
.data 0x00000014 # size
.data 0x1C00000A # 8000C8A0 => mulli r0, r0, 10
.data 0x57E407BD # 8000C8A4 => rlwinm. r4, r31, 0, 30, 30
.data 0x41820008 # 8000C8A8 => beq +0x00000008 /* 8000C8B0 */
.data 0x7FA00734 # 8000C8AC => extsh r0, r29
.data 0x4810605C # 8000C8B0 => b +0x0010605C /* 8011290C */
# region @ 8000C8C0 (16 bytes)
.data 0x8000C8C0 # address
.data 0x00000010 # size
.data 0x7000000F # 8000C8C0 => andi. r0, r0, 0x000F
.data 0x7000004F # 8000C8C4 => andi. r0, r0, 0x004F
.data 0x2C000004 # 8000C8C8 => cmpwi r0, 4
.data 0x4E800020 # 8000C8CC => blr
# region @ 8000D980 (20 bytes)
.data 0x8000D980 # address
.data 0x00000014 # size
.data 0x807C0000 # 8000D980 => lwz r3, [r28]
.data 0x2C030013 # 8000D984 => cmpwi r3, 19
.data 0x40820008 # 8000D988 => bne +0x00000008 /* 8000D990 */
.data 0x38600002 # 8000D98C => li r3, 0x0002
.data 0x482AE568 # 8000D990 => b +0x002AE568 /* 802BBEF8 */
# region @ 8000D9A0 (24 bytes)
.data 0x8000D9A0 # address
.data 0x00000018 # size
.data 0xC042FC88 # 8000D9A0 => lfs f2, [r2 - 0x0378]
.data 0x807E0030 # 8000D9A4 => lwz r3, [r30 + 0x0030]
.data 0x70630020 # 8000D9A8 => andi. r3, r3, 0x0020
.data 0x41820008 # 8000D9AC => beq +0x00000008 /* 8000D9B4 */
.data 0xC042FCA0 # 8000D9B0 => lfs f2, [r2 - 0x0360]
.data 0x483280A0 # 8000D9B4 => b +0x003280A0 /* 80335A54 */
# region @ 8000E1E0 (28 bytes)
.data 0x8000E1E0 # address
.data 0x0000001C # size
.data 0x7FC802A6 # 8000E1E0 => mflr r30
.data 0x38A00000 # 8000E1E4 => li r5, 0x0000
.data 0x38C0001E # 8000E1E8 => li r6, 0x001E
.data 0x38E00040 # 8000E1EC => li r7, 0x0040
.data 0x4807853D # 8000E1F0 => bl +0x0007853C /* 8008672C */
.data 0x7FC803A6 # 8000E1F4 => mtlr r30
.data 0x4E800020 # 8000E1F8 => blr
# region @ 80013084 (4 bytes)
.data 0x80013084 # address
.data 0x00000004 # size
.data 0x4BFFFCC0 # 80013084 => b -0x00000340 /* 80012D44 */
# region @ 800142F4 (4 bytes)
.data 0x800142F4 # address
.data 0x00000004 # size
.data 0x4BFF85CD # 800142F4 => bl -0x00007A34 /* 8000C8C0 */
# region @ 80015D1C (4 bytes)
.data 0x80015D1C # address
.data 0x00000004 # size
.data 0x4BFF6BA9 # 80015D1C => bl -0x00009458 /* 8000C8C4 */
# region @ 800917B4 (8 bytes)
.data 0x800917B4 # address
.data 0x00000008 # size
.data 0x4800024D # 800917B4 => bl +0x0000024C /* 80091A00 */
.data 0xB3C3032C # 800917B8 => sth [r3 + 0x032C], r30
# region @ 800BC9E8 (4 bytes)
.data 0x800BC9E8 # address
.data 0x00000004 # size
.data 0x48000010 # 800BC9E8 => b +0x00000010 /* 800BC9F8 */
# region @ 80101EB8 (4 bytes)
.data 0x80101EB8 # address
.data 0x00000004 # size
.data 0x60000000 # 80101EB8 => nop
# region @ 80104DEC (4 bytes)
.data 0x80104DEC # address
.data 0x00000004 # size
.data 0x4182000C # 80104DEC => beq +0x0000000C /* 80104DF8 */
# region @ 8010771C (4 bytes)
.data 0x8010771C # address
.data 0x00000004 # size
.data 0x4800000C # 8010771C => b +0x0000000C /* 80107728 */
# region @ 80107730 (4 bytes)
.data 0x80107730 # address
.data 0x00000004 # size
.data 0x7C030378 # 80107730 => mr r3, r0
# region @ 8010BC14 (4 bytes)
.data 0x8010BC14 # address
.data 0x00000004 # size
.data 0x4BEFF488 # 8010BC14 => b -0x00100B78 /* 8000B09C */
# region @ 8010E03C (4 bytes)
.data 0x8010E03C # address
.data 0x00000004 # size
.data 0x4BEFD078 # 8010E03C => b -0x00102F88 /* 8000B0B4 */
# region @ 80112908 (4 bytes)
.data 0x80112908 # address
.data 0x00000004 # size
.data 0x4BEF9F98 # 80112908 => b -0x00106068 /* 8000C8A0 */
# region @ 8011461C (4 bytes)
.data 0x8011461C # address
.data 0x00000004 # size
.data 0x38000012 # 8011461C => li r0, 0x0012
# region @ 80118854 (4 bytes)
.data 0x80118854 # address
.data 0x00000004 # size
.data 0x88040016 # 80118854 => lbz r0, [r4 + 0x0016]
# region @ 80118860 (4 bytes)
.data 0x80118860 # address
.data 0x00000004 # size
.data 0x88040017 # 80118860 => lbz r0, [r4 + 0x0017]
# region @ 80118F84 (4 bytes)
.data 0x80118F84 # address
.data 0x00000004 # size
.data 0x4BEF36BC # 80118F84 => b -0x0010C944 /* 8000C640 */
# region @ 8011CD34 (12 bytes)
.data 0x8011CD34 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CD34 => mr r3, r0
.data 0x3863FFFF # 8011CD38 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CD3C => b -0x00000018 /* 8011CD24 */
# region @ 8011CDF0 (12 bytes)
.data 0x8011CDF0 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CDF0 => mr r3, r0
.data 0x3863FFFF # 8011CDF4 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CDF8 => b -0x00000018 /* 8011CDE0 */
# region @ 8011CE40 (12 bytes)
.data 0x8011CE40 # address
.data 0x0000000C # size
.data 0x7C040378 # 8011CE40 => mr r4, r0
.data 0x3884FFFF # 8011CE44 => subi r4, r4, 0x0001
.data 0x4BFFFFE8 # 8011CE48 => b -0x00000018 /* 8011CE30 */
# region @ 801666E0 (8 bytes)
.data 0x801666E0 # address
.data 0x00000008 # size
.data 0x3C604005 # 801666E0 => lis r3, 0x4005
.data 0x4800009C # 801666E4 => b +0x0000009C /* 80166780 */
# region @ 8016677C (4 bytes)
.data 0x8016677C # address
.data 0x00000004 # size
.data 0x4800001C # 8016677C => b +0x0000001C /* 80166798 */
# region @ 80171010 (4 bytes)
.data 0x80171010 # address
.data 0x00000004 # size
.data 0x4BE9ABC0 # 80171010 => b -0x00165440 /* 8000BBD0 */
# region @ 80171030 (4 bytes)
.data 0x80171030 # address
.data 0x00000004 # size
.data 0x60800420 # 80171030 => ori r0, r4, 0x0420
# region @ 80184250 (4 bytes)
.data 0x80184250 # address
.data 0x00000004 # size
.data 0x4BE87378 # 80184250 => b -0x00178C88 /* 8000B5C8 */
# region @ 80184290 (4 bytes)
.data 0x80184290 # address
.data 0x00000004 # size
.data 0x60000000 # 80184290 => nop
# region @ 80189E20 (4 bytes)
.data 0x80189E20 # address
.data 0x00000004 # size
.data 0x60000000 # 80189E20 => nop
# region @ 801937A8 (4 bytes)
.data 0x801937A8 # address
.data 0x00000004 # size
.data 0x60000000 # 801937A8 => nop
# region @ 801B9BA0 (4 bytes)
.data 0x801B9BA0 # address
.data 0x00000004 # size
.data 0x4BE52868 # 801B9BA0 => b -0x001AD798 /* 8000C408 */
# region @ 801B9E74 (4 bytes)
.data 0x801B9E74 # address
.data 0x00000004 # size
.data 0x4BE51214 # 801B9E74 => b -0x001AEDEC /* 8000B088 */
# region @ 801C62C0 (4 bytes)
.data 0x801C62C0 # address
.data 0x00000004 # size
.data 0x389F02FC # 801C62C0 => addi r4, r31, 0x02FC
# region @ 801CA610 (4 bytes)
.data 0x801CA610 # address
.data 0x00000004 # size
.data 0x48000010 # 801CA610 => b +0x00000010 /* 801CA620 */
# region @ 8021D91C (4 bytes)
.data 0x8021D91C # address
.data 0x00000004 # size
.data 0x4BDEEDB4 # 8021D91C => b -0x0021124C /* 8000C6D0 */
# region @ 80220DDC (4 bytes)
.data 0x80220DDC # address
.data 0x00000004 # size
.data 0x4BDEB904 # 80220DDC => b -0x002146FC /* 8000C6E0 */
# region @ 80229C10 (4 bytes)
.data 0x80229C10 # address
.data 0x00000004 # size
.data 0x2C000001 # 80229C10 => cmpwi r0, 1
# region @ 8022A410 (4 bytes)
.data 0x8022A410 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022A410 => li r4, 0xFFFFFF00
# region @ 8022A440 (4 bytes)
.data 0x8022A440 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022A440 => li r4, 0xFFFFFE80
# region @ 8022A470 (4 bytes)
.data 0x8022A470 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022A470 => li r4, 0xFFFFFDB0
# region @ 8022D10C (4 bytes)
.data 0x8022D10C # address
.data 0x00000004 # size
.data 0x60000000 # 8022D10C => nop
# region @ 8022D840 (4 bytes)
.data 0x8022D840 # address
.data 0x00000004 # size
.data 0x41810630 # 8022D840 => bgt +0x00000630 /* 8022DE70 */
# region @ 8022DB34 (4 bytes)
.data 0x8022DB34 # address
.data 0x00000004 # size
.data 0x4181033C # 8022DB34 => bgt +0x0000033C /* 8022DE70 */
# region @ 8022DC28 (4 bytes)
.data 0x8022DC28 # address
.data 0x00000004 # size
.data 0x41810248 # 8022DC28 => bgt +0x00000248 /* 8022DE70 */
# region @ 8022EB64 (4 bytes)
.data 0x8022EB64 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022EB64 => li r4, 0xFFFFFF00
# region @ 8022EB94 (4 bytes)
.data 0x8022EB94 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022EB94 => li r4, 0xFFFFFE80
# region @ 8022EBC4 (4 bytes)
.data 0x8022EBC4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022EBC4 => li r4, 0xFFFFFDB0
# region @ 8022F370 (4 bytes)
.data 0x8022F370 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022F370 => li r4, 0xFFFFFF00
# region @ 8022F3A0 (4 bytes)
.data 0x8022F3A0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022F3A0 => li r4, 0xFFFFFE80
# region @ 8022F3D0 (4 bytes)
.data 0x8022F3D0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022F3D0 => li r4, 0xFFFFFDB0
# region @ 80230974 (4 bytes)
.data 0x80230974 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80230974 => li r4, 0xFFFFFF00
# region @ 802309A4 (4 bytes)
.data 0x802309A4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802309A4 => li r4, 0xFFFFFE80
# region @ 802309D4 (4 bytes)
.data 0x802309D4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802309D4 => li r4, 0xFFFFFDB0
# region @ 802316E4 (4 bytes)
.data 0x802316E4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802316E4 => li r4, 0xFFFFFF00
# region @ 80231714 (4 bytes)
.data 0x80231714 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80231714 => li r4, 0xFFFFFE80
# region @ 80231744 (4 bytes)
.data 0x80231744 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80231744 => li r4, 0xFFFFFDB0
# region @ 80231FD8 (4 bytes)
.data 0x80231FD8 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80231FD8 => li r4, 0xFFFFFF00
# region @ 80232010 (4 bytes)
.data 0x80232010 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80232010 => li r4, 0xFFFFFE80
# region @ 80232048 (4 bytes)
.data 0x80232048 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80232048 => li r4, 0xFFFFFDB0
# region @ 80234084 (4 bytes)
.data 0x80234084 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80234084 => li r4, 0xFFFFFF00
# region @ 802340B4 (4 bytes)
.data 0x802340B4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802340B4 => li r4, 0xFFFFFE80
# region @ 802340E4 (4 bytes)
.data 0x802340E4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802340E4 => li r4, 0xFFFFFDB0
# region @ 802366B0 (4 bytes)
.data 0x802366B0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802366B0 => li r4, 0xFFFFFF00
# region @ 802366EC (4 bytes)
.data 0x802366EC # address
.data 0x00000004 # size
.data 0x3880FE80 # 802366EC => li r4, 0xFFFFFE80
# region @ 80236728 (4 bytes)
.data 0x80236728 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80236728 => li r4, 0xFFFFFDB0
# region @ 80236E88 (4 bytes)
.data 0x80236E88 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80236E88 => li r4, 0xFFFFFF00
# region @ 80236EB8 (4 bytes)
.data 0x80236EB8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80236EB8 => li r4, 0xFFFFFE80
# region @ 80236EE8 (4 bytes)
.data 0x80236EE8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80236EE8 => li r4, 0xFFFFFDB0
# region @ 8023789C (4 bytes)
.data 0x8023789C # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023789C => li r4, 0xFFFFFF00
# region @ 802378CC (4 bytes)
.data 0x802378CC # address
.data 0x00000004 # size
.data 0x3880FE80 # 802378CC => li r4, 0xFFFFFE80
# region @ 802378FC (4 bytes)
.data 0x802378FC # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802378FC => li r4, 0xFFFFFDB0
# region @ 80238274 (4 bytes)
.data 0x80238274 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80238274 => li r4, 0xFFFFFF00
# region @ 802382A4 (4 bytes)
.data 0x802382A4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802382A4 => li r4, 0xFFFFFE80
# region @ 802382D4 (4 bytes)
.data 0x802382D4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802382D4 => li r4, 0xFFFFFDB0
# region @ 8023BBA4 (4 bytes)
.data 0x8023BBA4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023BBA4 => li r4, 0xFFFFFF00
# region @ 8023BBD4 (4 bytes)
.data 0x8023BBD4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023BBD4 => li r4, 0xFFFFFE80
# region @ 8023BC04 (4 bytes)
.data 0x8023BC04 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023BC04 => li r4, 0xFFFFFDB0
# region @ 80250AEC (4 bytes)
.data 0x80250AEC # address
.data 0x00000004 # size
.data 0x60000000 # 80250AEC => nop
# region @ 80268788 (4 bytes)
.data 0x80268788 # address
.data 0x00000004 # size
.data 0x60000000 # 80268788 => nop
# region @ 8026E2D4 (4 bytes)
.data 0x8026E2D4 # address
.data 0x00000004 # size
.data 0x3884AAFA # 8026E2D4 => subi r4, r4, 0x5506
# region @ 8026E3E8 (4 bytes)
.data 0x8026E3E8 # address
.data 0x00000004 # size
.data 0x3863AAFA # 8026E3E8 => subi r3, r3, 0x5506
# region @ 8026E470 (4 bytes)
.data 0x8026E470 # address
.data 0x00000004 # size
.data 0x3883AAFA # 8026E470 => subi r4, r3, 0x5506
# region @ 802BBEF4 (4 bytes)
.data 0x802BBEF4 # address
.data 0x00000004 # size
.data 0x4BD51A8C # 802BBEF4 => b -0x002AE574 /* 8000D980 */
# region @ 802FC2F4 (4 bytes)
.data 0x802FC2F4 # address
.data 0x00000004 # size
.data 0x2C030001 # 802FC2F4 => cmpwi r3, 1
# region @ 80301F58 (28 bytes)
.data 0x80301F58 # address
.data 0x0000001C # size
.data 0x48000020 # 80301F58 => b +0x00000020 /* 80301F78 */
.data 0x3863A830 # 80301F5C => subi r3, r3, 0x57D0
.data 0x800DB9A4 # 80301F60 => lwz r0, [r13 - 0x465C]
.data 0x2C000023 # 80301F64 => cmpwi r0, 35
.data 0x40820008 # 80301F68 => bne +0x00000008 /* 80301F70 */
.data 0x3863FB28 # 80301F6C => subi r3, r3, 0x04D8
.data 0x4800008C # 80301F70 => b +0x0000008C /* 80301FFC */
# region @ 80301FF8 (4 bytes)
.data 0x80301FF8 # address
.data 0x00000004 # size
.data 0x4BFFFF64 # 80301FF8 => b -0x0000009C /* 80301F5C */
# region @ 80335A50 (4 bytes)
.data 0x80335A50 # address
.data 0x00000004 # size
.data 0x4BCD7F50 # 80335A50 => b -0x003280B0 /* 8000D9A0 */
# region @ 80356814 (4 bytes)
.data 0x80356814 # address
.data 0x00000004 # size
.data 0x388001E8 # 80356814 => li r4, 0x01E8
# region @ 80356838 (4 bytes)
.data 0x80356838 # address
.data 0x00000004 # size
.data 0x4BCB79A9 # 80356838 => bl -0x00348658 /* 8000E1E0 */
# region @ 803568A8 (4 bytes)
.data 0x803568A8 # address
.data 0x00000004 # size
.data 0x388001E8 # 803568A8 => li r4, 0x01E8
# region @ 803568B8 (4 bytes)
.data 0x803568B8 # address
.data 0x00000004 # size
.data 0x4BCB7929 # 803568B8 => bl -0x003486D8 /* 8000E1E0 */
# region @ 804B3EF0 (8 bytes)
.data 0x804B3EF0 # address
.data 0x00000008 # size
.data 0x70808080 # 804B3EF0 => andi. r0, r4, 0x8080
.data 0x60707070 # 804B3EF4 => ori r16, r3, 0x7070
# region @ 804C76B4 (4 bytes)
.data 0x804C76B4 # address
.data 0x00000004 # size
.data 0x0000001E # 804C76B4 => .invalid
# region @ 804C770C (4 bytes)
.data 0x804C770C # address
.data 0x00000004 # size
.data 0x00000028 # 804C770C => .invalid
# region @ 804C7738 (4 bytes)
.data 0x804C7738 # address
.data 0x00000004 # size
.data 0x00000032 # 804C7738 => .invalid
# region @ 804C7764 (4 bytes)
.data 0x804C7764 # address
.data 0x00000004 # size
.data 0x0000003C # 804C7764 => .invalid
# region @ 804C7774 (4 bytes)
.data 0x804C7774 # address
.data 0x00000004 # size
.data 0x0018003C # 804C7774 => .invalid
# region @ 804C79CC (4 bytes)
.data 0x804C79CC # address
.data 0x00000004 # size
.data 0x00000028 # 804C79CC => .invalid
# region @ 804CC310 (4 bytes)
.data 0x804CC310 # address
.data 0x00000004 # size
.data 0xFF0074EE # 804CC310 => fsel f24, f0, f14, f19
# region @ 805CA274 (4 bytes)
.data 0x805CA274 # address
.data 0x00000004 # size
.data 0x435C0000 # 805CA274 => bc 26, 28, +0x00000000 /* 805CA274 */
# region @ 805CBF10 (4 bytes)
.data 0x805CBF10 # address
.data 0x00000004 # size
.data 0x46AFC800 # 805CBF10 => .invalid sc
# region @ 805CC1B0 (4 bytes)
.data 0x805CC1B0 # address
.data 0x00000004 # size
.data 0x43480000 # 805CC1B0 => bc 26, 8, +0x00000000 /* 805CC1B0 */
# end sentinel
.data 0x00000000 # address
.data 0x00000000 # size
@@ -1,564 +0,0 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
# region @ 8000B088 (88 bytes)
.data 0x8000B088 # address
.data 0x00000058 # size
.data 0x7FA3EB78 # 8000B088 => mr r3, r29
.data 0x38800000 # 8000B08C => li r4, 0x0000
.data 0x481AEB11 # 8000B090 => bl +0x001AEB10 /* 801B9BA0 */
.data 0x7FA3EB78 # 8000B094 => mr r3, r29
.data 0x481AEDE0 # 8000B098 => b +0x001AEDE0 /* 801B9E78 */
.data 0x881F0000 # 8000B09C => lbz r0, [r31]
.data 0x28090001 # 8000B0A0 => cmplwi r9, 1
.data 0x4082000C # 8000B0A4 => bne +0x0000000C /* 8000B0B0 */
.data 0x881F0001 # 8000B0A8 => lbz r0, [r31 + 0x0001]
.data 0x3BFF0002 # 8000B0AC => addi r31, r31, 0x0002
.data 0x48100B68 # 8000B0B0 => b +0x00100B68 /* 8010BC18 */
.data 0x39200000 # 8000B0B4 => li r9, 0x0000
.data 0x48100AF9 # 8000B0B8 => bl +0x00100AF8 /* 8010BBB0 */
.data 0x7F43D378 # 8000B0BC => mr r3, r26
.data 0x7F64DB78 # 8000B0C0 => mr r4, r27
.data 0x7F85E378 # 8000B0C4 => mr r5, r28
.data 0x7FA6EB78 # 8000B0C8 => mr r6, r29
.data 0x7FC7F378 # 8000B0CC => mr r7, r30
.data 0x7FE8FB78 # 8000B0D0 => mr r8, r31
.data 0x39200001 # 8000B0D4 => li r9, 0x0001
.data 0x48100AD9 # 8000B0D8 => bl +0x00100AD8 /* 8010BBB0 */
.data 0x48102F64 # 8000B0DC => b +0x00102F64 /* 8010E040 */
# region @ 8000B5C8 (20 bytes)
.data 0x8000B5C8 # address
.data 0x00000014 # size
.data 0x80630098 # 8000B5C8 => lwz r3, [r3 + 0x0098]
.data 0x483D59F1 # 8000B5CC => bl +0x003D59F0 /* 803E0FBC */
.data 0x807F042C # 8000B5D0 => lwz r3, [r31 + 0x042C]
.data 0x809F0430 # 8000B5D4 => lwz r4, [r31 + 0x0430]
.data 0x48178C7C # 8000B5D8 => b +0x00178C7C /* 80184254 */
# region @ 8000BBD0 (32 bytes)
.data 0x8000BBD0 # address
.data 0x00000020 # size
.data 0x809F0370 # 8000BBD0 => lwz r4, [r31 + 0x0370]
.data 0x3884FC00 # 8000BBD4 => subi r4, r4, 0x0400
.data 0x909F0370 # 8000BBD8 => stw [r31 + 0x0370], r4
.data 0x807F0014 # 8000BBDC => lwz r3, [r31 + 0x0014]
.data 0x28030000 # 8000BBE0 => cmplwi r3, 0
.data 0x41820008 # 8000BBE4 => beq +0x00000008 /* 8000BBEC */
.data 0x90830060 # 8000BBE8 => stw [r3 + 0x0060], r4
.data 0x48165428 # 8000BBEC => b +0x00165428 /* 80171014 */
# region @ 8000C3F8 (124 bytes)
.data 0x8000C3F8 # address
.data 0x0000007C # size
.data 0x28040000 # 8000C3F8 => cmplwi r4, 0
.data 0x4D820020 # 8000C3FC => beqlr
.data 0x9421FFF0 # 8000C400 => stwu [r1 - 0x0010], r1
.data 0x481AD7A0 # 8000C404 => b +0x001AD7A0 /* 801B9BA4 */
.data 0x9421FFE0 # 8000C408 => stwu [r1 - 0x0020], r1
.data 0x7C0802A6 # 8000C40C => mflr r0
.data 0x90010024 # 8000C410 => stw [r1 + 0x0024], r0
.data 0xBF410008 # 8000C414 => stmw [r1 + 0x0008], r26
.data 0x7C7F1B78 # 8000C418 => mr r31, r3
.data 0x4BFFFFDD # 8000C41C => bl -0x00000024 /* 8000C3F8 */
.data 0x3BC00000 # 8000C420 => li r30, 0x0000
.data 0x3BBF0D04 # 8000C424 => addi r29, r31, 0x0D04
.data 0x837F032C # 8000C428 => lwz r27, [r31 + 0x032C]
.data 0x839D0000 # 8000C42C => lwz r28, [r29]
.data 0x7F83E379 # 8000C430 => mr. r3, r28
.data 0x41820018 # 8000C434 => beq +0x00000018 /* 8000C44C */
.data 0x38800001 # 8000C438 => li r4, 0x0001
.data 0x480FED81 # 8000C43C => bl +0x000FED80 /* 8010B1BC */
.data 0x7F83E378 # 8000C440 => mr r3, r28
.data 0x38800001 # 8000C444 => li r4, 0x0001
.data 0x480FEEF1 # 8000C448 => bl +0x000FEEF0 /* 8010B338 */
.data 0x3BBD0004 # 8000C44C => addi r29, r29, 0x0004
.data 0x3BDE0001 # 8000C450 => addi r30, r30, 0x0001
.data 0x2C1E000D # 8000C454 => cmpwi r30, 13
.data 0x4180FFD4 # 8000C458 => blt -0x0000002C /* 8000C42C */
.data 0x937F032C # 8000C45C => stw [r31 + 0x032C], r27
.data 0xBB410008 # 8000C460 => lmw r26, [r1 + 0x0008]
.data 0x80010024 # 8000C464 => lwz r0, [r1 + 0x0024]
.data 0x7C0803A6 # 8000C468 => mtlr r0
.data 0x38210020 # 8000C46C => addi r1, r1, 0x0020
.data 0x4E800020 # 8000C470 => blr
# region @ 8000C640 (20 bytes)
.data 0x8000C640 # address
.data 0x00000014 # size
.data 0x54800673 # 8000C640 => rlwinm. r0, r4, 0, 25, 25
.data 0x41820008 # 8000C644 => beq +0x00000008 /* 8000C64C */
.data 0x38800000 # 8000C648 => li r4, 0x0000
.data 0x38040009 # 8000C64C => addi r0, r4, 0x0009
.data 0x4810C938 # 8000C650 => b +0x0010C938 /* 80118F88 */
# region @ 8000C6D0 (32 bytes)
.data 0x8000C6D0 # address
.data 0x00000020 # size
.data 0x38000001 # 8000C6D0 => li r0, 0x0001
.data 0x901D0054 # 8000C6D4 => stw [r29 + 0x0054], r0
.data 0x807D0024 # 8000C6D8 => lwz r3, [r29 + 0x0024]
.data 0x48211244 # 8000C6DC => b +0x00211244 /* 8021D920 */
.data 0x38000001 # 8000C6E0 => li r0, 0x0001
.data 0x901F0378 # 8000C6E4 => stw [r31 + 0x0378], r0
.data 0x807F0024 # 8000C6E8 => lwz r3, [r31 + 0x0024]
.data 0x482146F4 # 8000C6EC => b +0x002146F4 /* 80220DE0 */
# region @ 8000C8A0 (20 bytes)
.data 0x8000C8A0 # address
.data 0x00000014 # size
.data 0x1C00000A # 8000C8A0 => mulli r0, r0, 10
.data 0x57E407BD # 8000C8A4 => rlwinm. r4, r31, 0, 30, 30
.data 0x41820008 # 8000C8A8 => beq +0x00000008 /* 8000C8B0 */
.data 0x7FA00734 # 8000C8AC => extsh r0, r29
.data 0x4810605C # 8000C8B0 => b +0x0010605C /* 8011290C */
# region @ 8000C8C0 (16 bytes)
.data 0x8000C8C0 # address
.data 0x00000010 # size
.data 0x7000000F # 8000C8C0 => andi. r0, r0, 0x000F
.data 0x7000004F # 8000C8C4 => andi. r0, r0, 0x004F
.data 0x2C000004 # 8000C8C8 => cmpwi r0, 4
.data 0x4E800020 # 8000C8CC => blr
# region @ 8000D980 (20 bytes)
.data 0x8000D980 # address
.data 0x00000014 # size
.data 0x807C0000 # 8000D980 => lwz r3, [r28]
.data 0x2C030013 # 8000D984 => cmpwi r3, 19
.data 0x40820008 # 8000D988 => bne +0x00000008 /* 8000D990 */
.data 0x38600002 # 8000D98C => li r3, 0x0002
.data 0x482AE5AC # 8000D990 => b +0x002AE5AC /* 802BBF3C */
# region @ 8000D9A0 (24 bytes)
.data 0x8000D9A0 # address
.data 0x00000018 # size
.data 0xC042FC88 # 8000D9A0 => lfs f2, [r2 - 0x0378]
.data 0x807E0030 # 8000D9A4 => lwz r3, [r30 + 0x0030]
.data 0x70630020 # 8000D9A8 => andi. r3, r3, 0x0020
.data 0x41820008 # 8000D9AC => beq +0x00000008 /* 8000D9B4 */
.data 0xC042FCA0 # 8000D9B0 => lfs f2, [r2 - 0x0360]
.data 0x483280E4 # 8000D9B4 => b +0x003280E4 /* 80335A98 */
# region @ 8000E1E0 (28 bytes)
.data 0x8000E1E0 # address
.data 0x0000001C # size
.data 0x7FC802A6 # 8000E1E0 => mflr r30
.data 0x38A00000 # 8000E1E4 => li r5, 0x0000
.data 0x38C0001E # 8000E1E8 => li r6, 0x001E
.data 0x38E00040 # 8000E1EC => li r7, 0x0040
.data 0x4807853D # 8000E1F0 => bl +0x0007853C /* 8008672C */
.data 0x7FC803A6 # 8000E1F4 => mtlr r30
.data 0x4E800020 # 8000E1F8 => blr
# region @ 80013084 (4 bytes)
.data 0x80013084 # address
.data 0x00000004 # size
.data 0x4BFFFCC0 # 80013084 => b -0x00000340 /* 80012D44 */
# region @ 800142F4 (4 bytes)
.data 0x800142F4 # address
.data 0x00000004 # size
.data 0x4BFF85CD # 800142F4 => bl -0x00007A34 /* 8000C8C0 */
# region @ 80015D1C (4 bytes)
.data 0x80015D1C # address
.data 0x00000004 # size
.data 0x4BFF6BA9 # 80015D1C => bl -0x00009458 /* 8000C8C4 */
# region @ 800917B4 (8 bytes)
.data 0x800917B4 # address
.data 0x00000008 # size
.data 0x4800024D # 800917B4 => bl +0x0000024C /* 80091A00 */
.data 0xB3C3032C # 800917B8 => sth [r3 + 0x032C], r30
# region @ 800BC9E8 (4 bytes)
.data 0x800BC9E8 # address
.data 0x00000004 # size
.data 0x48000010 # 800BC9E8 => b +0x00000010 /* 800BC9F8 */
# region @ 80101EB8 (4 bytes)
.data 0x80101EB8 # address
.data 0x00000004 # size
.data 0x60000000 # 80101EB8 => nop
# region @ 80104DEC (4 bytes)
.data 0x80104DEC # address
.data 0x00000004 # size
.data 0x4182000C # 80104DEC => beq +0x0000000C /* 80104DF8 */
# region @ 8010771C (4 bytes)
.data 0x8010771C # address
.data 0x00000004 # size
.data 0x4800000C # 8010771C => b +0x0000000C /* 80107728 */
# region @ 80107730 (4 bytes)
.data 0x80107730 # address
.data 0x00000004 # size
.data 0x7C030378 # 80107730 => mr r3, r0
# region @ 8010BC14 (4 bytes)
.data 0x8010BC14 # address
.data 0x00000004 # size
.data 0x4BEFF488 # 8010BC14 => b -0x00100B78 /* 8000B09C */
# region @ 8010E03C (4 bytes)
.data 0x8010E03C # address
.data 0x00000004 # size
.data 0x4BEFD078 # 8010E03C => b -0x00102F88 /* 8000B0B4 */
# region @ 80112908 (4 bytes)
.data 0x80112908 # address
.data 0x00000004 # size
.data 0x4BEF9F98 # 80112908 => b -0x00106068 /* 8000C8A0 */
# region @ 8011461C (4 bytes)
.data 0x8011461C # address
.data 0x00000004 # size
.data 0x38000012 # 8011461C => li r0, 0x0012
# region @ 80118854 (4 bytes)
.data 0x80118854 # address
.data 0x00000004 # size
.data 0x88040016 # 80118854 => lbz r0, [r4 + 0x0016]
# region @ 80118860 (4 bytes)
.data 0x80118860 # address
.data 0x00000004 # size
.data 0x88040017 # 80118860 => lbz r0, [r4 + 0x0017]
# region @ 80118F84 (4 bytes)
.data 0x80118F84 # address
.data 0x00000004 # size
.data 0x4BEF36BC # 80118F84 => b -0x0010C944 /* 8000C640 */
# region @ 8011CD34 (12 bytes)
.data 0x8011CD34 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CD34 => mr r3, r0
.data 0x3863FFFF # 8011CD38 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CD3C => b -0x00000018 /* 8011CD24 */
# region @ 8011CDF0 (12 bytes)
.data 0x8011CDF0 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CDF0 => mr r3, r0
.data 0x3863FFFF # 8011CDF4 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CDF8 => b -0x00000018 /* 8011CDE0 */
# region @ 8011CE40 (12 bytes)
.data 0x8011CE40 # address
.data 0x0000000C # size
.data 0x7C040378 # 8011CE40 => mr r4, r0
.data 0x3884FFFF # 8011CE44 => subi r4, r4, 0x0001
.data 0x4BFFFFE8 # 8011CE48 => b -0x00000018 /* 8011CE30 */
# region @ 801666E0 (8 bytes)
.data 0x801666E0 # address
.data 0x00000008 # size
.data 0x3C604005 # 801666E0 => lis r3, 0x4005
.data 0x4800009C # 801666E4 => b +0x0000009C /* 80166780 */
# region @ 8016677C (4 bytes)
.data 0x8016677C # address
.data 0x00000004 # size
.data 0x4800001C # 8016677C => b +0x0000001C /* 80166798 */
# region @ 80171010 (4 bytes)
.data 0x80171010 # address
.data 0x00000004 # size
.data 0x4BE9ABC0 # 80171010 => b -0x00165440 /* 8000BBD0 */
# region @ 80171030 (4 bytes)
.data 0x80171030 # address
.data 0x00000004 # size
.data 0x60800420 # 80171030 => ori r0, r4, 0x0420
# region @ 80184250 (4 bytes)
.data 0x80184250 # address
.data 0x00000004 # size
.data 0x4BE87378 # 80184250 => b -0x00178C88 /* 8000B5C8 */
# region @ 80184290 (4 bytes)
.data 0x80184290 # address
.data 0x00000004 # size
.data 0x60000000 # 80184290 => nop
# region @ 80189E20 (4 bytes)
.data 0x80189E20 # address
.data 0x00000004 # size
.data 0x60000000 # 80189E20 => nop
# region @ 801937A8 (4 bytes)
.data 0x801937A8 # address
.data 0x00000004 # size
.data 0x60000000 # 801937A8 => nop
# region @ 801B9BA0 (4 bytes)
.data 0x801B9BA0 # address
.data 0x00000004 # size
.data 0x4BE52868 # 801B9BA0 => b -0x001AD798 /* 8000C408 */
# region @ 801B9E74 (4 bytes)
.data 0x801B9E74 # address
.data 0x00000004 # size
.data 0x4BE51214 # 801B9E74 => b -0x001AEDEC /* 8000B088 */
# region @ 801C62C0 (4 bytes)
.data 0x801C62C0 # address
.data 0x00000004 # size
.data 0x389F02FC # 801C62C0 => addi r4, r31, 0x02FC
# region @ 801CA610 (4 bytes)
.data 0x801CA610 # address
.data 0x00000004 # size
.data 0x48000010 # 801CA610 => b +0x00000010 /* 801CA620 */
# region @ 8021D91C (4 bytes)
.data 0x8021D91C # address
.data 0x00000004 # size
.data 0x4BDEEDB4 # 8021D91C => b -0x0021124C /* 8000C6D0 */
# region @ 80220DDC (4 bytes)
.data 0x80220DDC # address
.data 0x00000004 # size
.data 0x4BDEB904 # 80220DDC => b -0x002146FC /* 8000C6E0 */
# region @ 80229C10 (4 bytes)
.data 0x80229C10 # address
.data 0x00000004 # size
.data 0x2C000001 # 80229C10 => cmpwi r0, 1
# region @ 8022A410 (4 bytes)
.data 0x8022A410 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022A410 => li r4, 0xFFFFFF00
# region @ 8022A440 (4 bytes)
.data 0x8022A440 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022A440 => li r4, 0xFFFFFE80
# region @ 8022A470 (4 bytes)
.data 0x8022A470 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022A470 => li r4, 0xFFFFFDB0
# region @ 8022D10C (4 bytes)
.data 0x8022D10C # address
.data 0x00000004 # size
.data 0x60000000 # 8022D10C => nop
# region @ 8022D840 (4 bytes)
.data 0x8022D840 # address
.data 0x00000004 # size
.data 0x41810630 # 8022D840 => bgt +0x00000630 /* 8022DE70 */
# region @ 8022DB34 (4 bytes)
.data 0x8022DB34 # address
.data 0x00000004 # size
.data 0x4181033C # 8022DB34 => bgt +0x0000033C /* 8022DE70 */
# region @ 8022DC28 (4 bytes)
.data 0x8022DC28 # address
.data 0x00000004 # size
.data 0x41810248 # 8022DC28 => bgt +0x00000248 /* 8022DE70 */
# region @ 8022EB64 (4 bytes)
.data 0x8022EB64 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022EB64 => li r4, 0xFFFFFF00
# region @ 8022EB94 (4 bytes)
.data 0x8022EB94 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022EB94 => li r4, 0xFFFFFE80
# region @ 8022EBC4 (4 bytes)
.data 0x8022EBC4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022EBC4 => li r4, 0xFFFFFDB0
# region @ 8022F370 (4 bytes)
.data 0x8022F370 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022F370 => li r4, 0xFFFFFF00
# region @ 8022F3A0 (4 bytes)
.data 0x8022F3A0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022F3A0 => li r4, 0xFFFFFE80
# region @ 8022F3D0 (4 bytes)
.data 0x8022F3D0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022F3D0 => li r4, 0xFFFFFDB0
# region @ 80230974 (4 bytes)
.data 0x80230974 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80230974 => li r4, 0xFFFFFF00
# region @ 802309A4 (4 bytes)
.data 0x802309A4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802309A4 => li r4, 0xFFFFFE80
# region @ 802309D4 (4 bytes)
.data 0x802309D4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802309D4 => li r4, 0xFFFFFDB0
# region @ 802316E4 (4 bytes)
.data 0x802316E4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802316E4 => li r4, 0xFFFFFF00
# region @ 80231714 (4 bytes)
.data 0x80231714 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80231714 => li r4, 0xFFFFFE80
# region @ 80231744 (4 bytes)
.data 0x80231744 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80231744 => li r4, 0xFFFFFDB0
# region @ 80231FD8 (4 bytes)
.data 0x80231FD8 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80231FD8 => li r4, 0xFFFFFF00
# region @ 80232010 (4 bytes)
.data 0x80232010 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80232010 => li r4, 0xFFFFFE80
# region @ 80232048 (4 bytes)
.data 0x80232048 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80232048 => li r4, 0xFFFFFDB0
# region @ 80234084 (4 bytes)
.data 0x80234084 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80234084 => li r4, 0xFFFFFF00
# region @ 802340B4 (4 bytes)
.data 0x802340B4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802340B4 => li r4, 0xFFFFFE80
# region @ 802340E4 (4 bytes)
.data 0x802340E4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802340E4 => li r4, 0xFFFFFDB0
# region @ 802366B0 (4 bytes)
.data 0x802366B0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802366B0 => li r4, 0xFFFFFF00
# region @ 802366EC (4 bytes)
.data 0x802366EC # address
.data 0x00000004 # size
.data 0x3880FE80 # 802366EC => li r4, 0xFFFFFE80
# region @ 80236728 (4 bytes)
.data 0x80236728 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80236728 => li r4, 0xFFFFFDB0
# region @ 80236E88 (4 bytes)
.data 0x80236E88 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80236E88 => li r4, 0xFFFFFF00
# region @ 80236EB8 (4 bytes)
.data 0x80236EB8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80236EB8 => li r4, 0xFFFFFE80
# region @ 80236EE8 (4 bytes)
.data 0x80236EE8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80236EE8 => li r4, 0xFFFFFDB0
# region @ 8023789C (4 bytes)
.data 0x8023789C # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023789C => li r4, 0xFFFFFF00
# region @ 802378CC (4 bytes)
.data 0x802378CC # address
.data 0x00000004 # size
.data 0x3880FE80 # 802378CC => li r4, 0xFFFFFE80
# region @ 802378FC (4 bytes)
.data 0x802378FC # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802378FC => li r4, 0xFFFFFDB0
# region @ 80238274 (4 bytes)
.data 0x80238274 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80238274 => li r4, 0xFFFFFF00
# region @ 802382A4 (4 bytes)
.data 0x802382A4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802382A4 => li r4, 0xFFFFFE80
# region @ 802382D4 (4 bytes)
.data 0x802382D4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802382D4 => li r4, 0xFFFFFDB0
# region @ 8023BBA4 (4 bytes)
.data 0x8023BBA4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023BBA4 => li r4, 0xFFFFFF00
# region @ 8023BBD4 (4 bytes)
.data 0x8023BBD4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023BBD4 => li r4, 0xFFFFFE80
# region @ 8023BC04 (4 bytes)
.data 0x8023BC04 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023BC04 => li r4, 0xFFFFFDB0
# region @ 80250AEC (4 bytes)
.data 0x80250AEC # address
.data 0x00000004 # size
.data 0x60000000 # 80250AEC => nop
# region @ 80268788 (4 bytes)
.data 0x80268788 # address
.data 0x00000004 # size
.data 0x60000000 # 80268788 => nop
# region @ 8026E2D4 (4 bytes)
.data 0x8026E2D4 # address
.data 0x00000004 # size
.data 0x3884AAFA # 8026E2D4 => subi r4, r4, 0x5506
# region @ 8026E3E8 (4 bytes)
.data 0x8026E3E8 # address
.data 0x00000004 # size
.data 0x3863AAFA # 8026E3E8 => subi r3, r3, 0x5506
# region @ 8026E470 (4 bytes)
.data 0x8026E470 # address
.data 0x00000004 # size
.data 0x3883AAFA # 8026E470 => subi r4, r3, 0x5506
# region @ 802BBF38 (4 bytes)
.data 0x802BBF38 # address
.data 0x00000004 # size
.data 0x4BD51A48 # 802BBF38 => b -0x002AE5B8 /* 8000D980 */
# region @ 802FC338 (4 bytes)
.data 0x802FC338 # address
.data 0x00000004 # size
.data 0x2C030001 # 802FC338 => cmpwi r3, 1
# region @ 80301F9C (28 bytes)
.data 0x80301F9C # address
.data 0x0000001C # size
.data 0x48000020 # 80301F9C => b +0x00000020 /* 80301FBC */
.data 0x3863A830 # 80301FA0 => subi r3, r3, 0x57D0
.data 0x800DB9A4 # 80301FA4 => lwz r0, [r13 - 0x465C]
.data 0x2C000023 # 80301FA8 => cmpwi r0, 35
.data 0x40820008 # 80301FAC => bne +0x00000008 /* 80301FB4 */
.data 0x3863FB28 # 80301FB0 => subi r3, r3, 0x04D8
.data 0x4800008C # 80301FB4 => b +0x0000008C /* 80302040 */
# region @ 8030203C (4 bytes)
.data 0x8030203C # address
.data 0x00000004 # size
.data 0x4BFFFF64 # 8030203C => b -0x0000009C /* 80301FA0 */
# region @ 80335A94 (4 bytes)
.data 0x80335A94 # address
.data 0x00000004 # size
.data 0x4BCD7F0C # 80335A94 => b -0x003280F4 /* 8000D9A0 */
# region @ 80356858 (4 bytes)
.data 0x80356858 # address
.data 0x00000004 # size
.data 0x388001E8 # 80356858 => li r4, 0x01E8
# region @ 8035687C (4 bytes)
.data 0x8035687C # address
.data 0x00000004 # size
.data 0x4BCB7965 # 8035687C => bl -0x0034869C /* 8000E1E0 */
# region @ 803568EC (4 bytes)
.data 0x803568EC # address
.data 0x00000004 # size
.data 0x388001E8 # 803568EC => li r4, 0x01E8
# region @ 803568FC (4 bytes)
.data 0x803568FC # address
.data 0x00000004 # size
.data 0x4BCB78E5 # 803568FC => bl -0x0034871C /* 8000E1E0 */
# region @ 804B43D0 (8 bytes)
.data 0x804B43D0 # address
.data 0x00000008 # size
.data 0x70808080 # 804B43D0 => andi. r0, r4, 0x8080
.data 0x60707070 # 804B43D4 => ori r16, r3, 0x7070
# region @ 804C7B94 (4 bytes)
.data 0x804C7B94 # address
.data 0x00000004 # size
.data 0x0000001E # 804C7B94 => .invalid
# region @ 804C7BEC (4 bytes)
.data 0x804C7BEC # address
.data 0x00000004 # size
.data 0x00000028 # 804C7BEC => .invalid
# region @ 804C7C18 (4 bytes)
.data 0x804C7C18 # address
.data 0x00000004 # size
.data 0x00000032 # 804C7C18 => .invalid
# region @ 804C7C44 (4 bytes)
.data 0x804C7C44 # address
.data 0x00000004 # size
.data 0x0000003C # 804C7C44 => .invalid
# region @ 804C7C54 (4 bytes)
.data 0x804C7C54 # address
.data 0x00000004 # size
.data 0x0018003C # 804C7C54 => .invalid
# region @ 804C7EAC (4 bytes)
.data 0x804C7EAC # address
.data 0x00000004 # size
.data 0x00000028 # 804C7EAC => .invalid
# region @ 804CC7F0 (4 bytes)
.data 0x804CC7F0 # address
.data 0x00000004 # size
.data 0xFF0074EE # 804CC7F0 => fsel f24, f0, f14, f19
# region @ 805D1294 (4 bytes)
.data 0x805D1294 # address
.data 0x00000004 # size
.data 0x435C0000 # 805D1294 => bc 26, 28, +0x00000000 /* 805D1294 */
# region @ 805D2F30 (4 bytes)
.data 0x805D2F30 # address
.data 0x00000004 # size
.data 0x46AFC800 # 805D2F30 => .invalid sc
# region @ 805D31D0 (4 bytes)
.data 0x805D31D0 # address
.data 0x00000004 # size
.data 0x43480000 # 805D31D0 => bc 26, 8, +0x00000000 /* 805D31D0 */
# end sentinel
.data 0x00000000 # address
.data 0x00000000 # size
@@ -1,552 +0,0 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
# region @ 8000B088 (88 bytes)
.data 0x8000B088 # address
.data 0x00000058 # size
.data 0x7FA3EB78 # 8000B088 => mr r3, r29
.data 0x38800000 # 8000B08C => li r4, 0x0000
.data 0x481AECC1 # 8000B090 => bl +0x001AECC0 /* 801B9D50 */
.data 0x7FA3EB78 # 8000B094 => mr r3, r29
.data 0x481AEF90 # 8000B098 => b +0x001AEF90 /* 801BA028 */
.data 0x881F0000 # 8000B09C => lbz r0, [r31]
.data 0x28090001 # 8000B0A0 => cmplwi r9, 1
.data 0x4082000C # 8000B0A4 => bne +0x0000000C /* 8000B0B0 */
.data 0x881F0001 # 8000B0A8 => lbz r0, [r31 + 0x0001]
.data 0x3BFF0002 # 8000B0AC => addi r31, r31, 0x0002
.data 0x48100A54 # 8000B0B0 => b +0x00100A54 /* 8010BB04 */
.data 0x39200000 # 8000B0B4 => li r9, 0x0000
.data 0x481009E5 # 8000B0B8 => bl +0x001009E4 /* 8010BA9C */
.data 0x7F43D378 # 8000B0BC => mr r3, r26
.data 0x7F64DB78 # 8000B0C0 => mr r4, r27
.data 0x7F85E378 # 8000B0C4 => mr r5, r28
.data 0x7FA6EB78 # 8000B0C8 => mr r6, r29
.data 0x7FC7F378 # 8000B0CC => mr r7, r30
.data 0x7FE8FB78 # 8000B0D0 => mr r8, r31
.data 0x39200001 # 8000B0D4 => li r9, 0x0001
.data 0x481009C5 # 8000B0D8 => bl +0x001009C4 /* 8010BA9C */
.data 0x48102E5C # 8000B0DC => b +0x00102E5C /* 8010DF38 */
# region @ 8000B5C8 (20 bytes)
.data 0x8000B5C8 # address
.data 0x00000014 # size
.data 0x80630098 # 8000B5C8 => lwz r3, [r3 + 0x0098]
.data 0x483D90F1 # 8000B5CC => bl +0x003D90F0 /* 803E46BC */
.data 0x807F042C # 8000B5D0 => lwz r3, [r31 + 0x042C]
.data 0x809F0430 # 8000B5D4 => lwz r4, [r31 + 0x0430]
.data 0x48178DB0 # 8000B5D8 => b +0x00178DB0 /* 80184388 */
# region @ 8000BBD0 (32 bytes)
.data 0x8000BBD0 # address
.data 0x00000020 # size
.data 0x809F0370 # 8000BBD0 => lwz r4, [r31 + 0x0370]
.data 0x3884FC00 # 8000BBD4 => subi r4, r4, 0x0400
.data 0x909F0370 # 8000BBD8 => stw [r31 + 0x0370], r4
.data 0x807F0014 # 8000BBDC => lwz r3, [r31 + 0x0014]
.data 0x28030000 # 8000BBE0 => cmplwi r3, 0
.data 0x41820008 # 8000BBE4 => beq +0x00000008 /* 8000BBEC */
.data 0x90830060 # 8000BBE8 => stw [r3 + 0x0060], r4
.data 0x48165548 # 8000BBEC => b +0x00165548 /* 80171134 */
# region @ 8000C3F8 (124 bytes)
.data 0x8000C3F8 # address
.data 0x0000007C # size
.data 0x28040000 # 8000C3F8 => cmplwi r4, 0
.data 0x4D820020 # 8000C3FC => beqlr
.data 0x9421FFF0 # 8000C400 => stwu [r1 - 0x0010], r1
.data 0x481AD950 # 8000C404 => b +0x001AD950 /* 801B9D54 */
.data 0x9421FFE0 # 8000C408 => stwu [r1 - 0x0020], r1
.data 0x7C0802A6 # 8000C40C => mflr r0
.data 0x90010024 # 8000C410 => stw [r1 + 0x0024], r0
.data 0xBF410008 # 8000C414 => stmw [r1 + 0x0008], r26
.data 0x7C7F1B78 # 8000C418 => mr r31, r3
.data 0x4BFFFFDD # 8000C41C => bl -0x00000024 /* 8000C3F8 */
.data 0x3BC00000 # 8000C420 => li r30, 0x0000
.data 0x3BBF0D04 # 8000C424 => addi r29, r31, 0x0D04
.data 0x837F032C # 8000C428 => lwz r27, [r31 + 0x032C]
.data 0x839D0000 # 8000C42C => lwz r28, [r29]
.data 0x7F83E379 # 8000C430 => mr. r3, r28
.data 0x41820018 # 8000C434 => beq +0x00000018 /* 8000C44C */
.data 0x38800001 # 8000C438 => li r4, 0x0001
.data 0x480FEC6D # 8000C43C => bl +0x000FEC6C /* 8010B0A8 */
.data 0x7F83E378 # 8000C440 => mr r3, r28
.data 0x38800001 # 8000C444 => li r4, 0x0001
.data 0x480FEDDD # 8000C448 => bl +0x000FEDDC /* 8010B224 */
.data 0x3BBD0004 # 8000C44C => addi r29, r29, 0x0004
.data 0x3BDE0001 # 8000C450 => addi r30, r30, 0x0001
.data 0x2C1E000D # 8000C454 => cmpwi r30, 13
.data 0x4180FFD4 # 8000C458 => blt -0x0000002C /* 8000C42C */
.data 0x937F032C # 8000C45C => stw [r31 + 0x032C], r27
.data 0xBB410008 # 8000C460 => lmw r26, [r1 + 0x0008]
.data 0x80010024 # 8000C464 => lwz r0, [r1 + 0x0024]
.data 0x7C0803A6 # 8000C468 => mtlr r0
.data 0x38210020 # 8000C46C => addi r1, r1, 0x0020
.data 0x4E800020 # 8000C470 => blr
# region @ 8000C640 (20 bytes)
.data 0x8000C640 # address
.data 0x00000014 # size
.data 0x54800673 # 8000C640 => rlwinm. r0, r4, 0, 25, 25
.data 0x41820008 # 8000C644 => beq +0x00000008 /* 8000C64C */
.data 0x38800000 # 8000C648 => li r4, 0x0000
.data 0x38040009 # 8000C64C => addi r0, r4, 0x0009
.data 0x4810C858 # 8000C650 => b +0x0010C858 /* 80118EA8 */
# region @ 8000C6D0 (32 bytes)
.data 0x8000C6D0 # address
.data 0x00000020 # size
.data 0x38000001 # 8000C6D0 => li r0, 0x0001
.data 0x901D0054 # 8000C6D4 => stw [r29 + 0x0054], r0
.data 0x807D0024 # 8000C6D8 => lwz r3, [r29 + 0x0024]
.data 0x482122F8 # 8000C6DC => b +0x002122F8 /* 8021E9D4 */
.data 0x38000001 # 8000C6E0 => li r0, 0x0001
.data 0x901F0378 # 8000C6E4 => stw [r31 + 0x0378], r0
.data 0x807F0024 # 8000C6E8 => lwz r3, [r31 + 0x0024]
.data 0x482157A8 # 8000C6EC => b +0x002157A8 /* 80221E94 */
# region @ 8000C8A0 (20 bytes)
.data 0x8000C8A0 # address
.data 0x00000014 # size
.data 0x1C00000A # 8000C8A0 => mulli r0, r0, 10
.data 0x57E407BD # 8000C8A4 => rlwinm. r4, r31, 0, 30, 30
.data 0x41820008 # 8000C8A8 => beq +0x00000008 /* 8000C8B0 */
.data 0x7FA00734 # 8000C8AC => extsh r0, r29
.data 0x48105F54 # 8000C8B0 => b +0x00105F54 /* 80112804 */
# region @ 8000C8C0 (16 bytes)
.data 0x8000C8C0 # address
.data 0x00000010 # size
.data 0x7000000F # 8000C8C0 => andi. r0, r0, 0x000F
.data 0x7000004F # 8000C8C4 => andi. r0, r0, 0x004F
.data 0x2C000004 # 8000C8C8 => cmpwi r0, 4
.data 0x4E800020 # 8000C8CC => blr
# region @ 8000D980 (20 bytes)
.data 0x8000D980 # address
.data 0x00000014 # size
.data 0x807C0000 # 8000D980 => lwz r3, [r28]
.data 0x2C030013 # 8000D984 => cmpwi r3, 19
.data 0x40820008 # 8000D988 => bne +0x00000008 /* 8000D990 */
.data 0x38600002 # 8000D98C => li r3, 0x0002
.data 0x482AFAE8 # 8000D990 => b +0x002AFAE8 /* 802BD478 */
# region @ 8000D9A0 (24 bytes)
.data 0x8000D9A0 # address
.data 0x00000018 # size
.data 0xC042FC88 # 8000D9A0 => lfs f2, [r2 - 0x0378]
.data 0x807E0030 # 8000D9A4 => lwz r3, [r30 + 0x0030]
.data 0x70630020 # 8000D9A8 => andi. r3, r3, 0x0020
.data 0x41820008 # 8000D9AC => beq +0x00000008 /* 8000D9B4 */
.data 0xC042FCA0 # 8000D9B0 => lfs f2, [r2 - 0x0360]
.data 0x48329BC0 # 8000D9B4 => b +0x00329BC0 /* 80337574 */
# region @ 8000E1E0 (28 bytes)
.data 0x8000E1E0 # address
.data 0x0000001C # size
.data 0x7FC802A6 # 8000E1E0 => mflr r30
.data 0x38A00000 # 8000E1E4 => li r5, 0x0000
.data 0x38C0001E # 8000E1E8 => li r6, 0x001E
.data 0x38E00040 # 8000E1EC => li r7, 0x0040
.data 0x480786D5 # 8000E1F0 => bl +0x000786D4 /* 800868C4 */
.data 0x7FC803A6 # 8000E1F4 => mtlr r30
.data 0x4E800020 # 8000E1F8 => blr
# region @ 8001304C (4 bytes)
.data 0x8001304C # address
.data 0x00000004 # size
.data 0x4BFFFCC0 # 8001304C => b -0x00000340 /* 80012D0C */
# region @ 800142BC (4 bytes)
.data 0x800142BC # address
.data 0x00000004 # size
.data 0x4BFF8605 # 800142BC => bl -0x000079FC /* 8000C8C0 */
# region @ 80015CE4 (4 bytes)
.data 0x80015CE4 # address
.data 0x00000004 # size
.data 0x4BFF6BE1 # 80015CE4 => bl -0x00009420 /* 8000C8C4 */
# region @ 8009194C (8 bytes)
.data 0x8009194C # address
.data 0x00000008 # size
.data 0x4800024D # 8009194C => bl +0x0000024C /* 80091B98 */
.data 0xB3C3032C # 80091950 => sth [r3 + 0x032C], r30
# region @ 800BCB90 (4 bytes)
.data 0x800BCB90 # address
.data 0x00000004 # size
.data 0x48000010 # 800BCB90 => b +0x00000010 /* 800BCBA0 */
# region @ 80104CB4 (4 bytes)
.data 0x80104CB4 # address
.data 0x00000004 # size
.data 0x4182000C # 80104CB4 => beq +0x0000000C /* 80104CC0 */
# region @ 801075E4 (4 bytes)
.data 0x801075E4 # address
.data 0x00000004 # size
.data 0x4800000C # 801075E4 => b +0x0000000C /* 801075F0 */
# region @ 801075F8 (4 bytes)
.data 0x801075F8 # address
.data 0x00000004 # size
.data 0x7C030378 # 801075F8 => mr r3, r0
# region @ 8010BB00 (4 bytes)
.data 0x8010BB00 # address
.data 0x00000004 # size
.data 0x4BEFF59C # 8010BB00 => b -0x00100A64 /* 8000B09C */
# region @ 8010DF34 (4 bytes)
.data 0x8010DF34 # address
.data 0x00000004 # size
.data 0x4BEFD180 # 8010DF34 => b -0x00102E80 /* 8000B0B4 */
# region @ 80112800 (4 bytes)
.data 0x80112800 # address
.data 0x00000004 # size
.data 0x4BEFA0A0 # 80112800 => b -0x00105F60 /* 8000C8A0 */
# region @ 80114534 (4 bytes)
.data 0x80114534 # address
.data 0x00000004 # size
.data 0x38000012 # 80114534 => li r0, 0x0012
# region @ 80118774 (4 bytes)
.data 0x80118774 # address
.data 0x00000004 # size
.data 0x88040016 # 80118774 => lbz r0, [r4 + 0x0016]
# region @ 80118780 (4 bytes)
.data 0x80118780 # address
.data 0x00000004 # size
.data 0x88040017 # 80118780 => lbz r0, [r4 + 0x0017]
# region @ 80118EA4 (4 bytes)
.data 0x80118EA4 # address
.data 0x00000004 # size
.data 0x4BEF379C # 80118EA4 => b -0x0010C864 /* 8000C640 */
# region @ 8011CC7C (12 bytes)
.data 0x8011CC7C # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CC7C => mr r3, r0
.data 0x3863FFFF # 8011CC80 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CC84 => b -0x00000018 /* 8011CC6C */
# region @ 8011CD38 (12 bytes)
.data 0x8011CD38 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CD38 => mr r3, r0
.data 0x3863FFFF # 8011CD3C => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CD40 => b -0x00000018 /* 8011CD28 */
# region @ 8011CD88 (12 bytes)
.data 0x8011CD88 # address
.data 0x0000000C # size
.data 0x7C040378 # 8011CD88 => mr r4, r0
.data 0x3884FFFF # 8011CD8C => subi r4, r4, 0x0001
.data 0x4BFFFFE8 # 8011CD90 => b -0x00000018 /* 8011CD78 */
# region @ 80166800 (8 bytes)
.data 0x80166800 # address
.data 0x00000008 # size
.data 0x3C604005 # 80166800 => lis r3, 0x4005
.data 0x4800009C # 80166804 => b +0x0000009C /* 801668A0 */
# region @ 8016689C (4 bytes)
.data 0x8016689C # address
.data 0x00000004 # size
.data 0x4800001C # 8016689C => b +0x0000001C /* 801668B8 */
# region @ 80171130 (4 bytes)
.data 0x80171130 # address
.data 0x00000004 # size
.data 0x4BE9AAA0 # 80171130 => b -0x00165560 /* 8000BBD0 */
# region @ 80171150 (4 bytes)
.data 0x80171150 # address
.data 0x00000004 # size
.data 0x60800420 # 80171150 => ori r0, r4, 0x0420
# region @ 80184384 (4 bytes)
.data 0x80184384 # address
.data 0x00000004 # size
.data 0x4BE87244 # 80184384 => b -0x00178DBC /* 8000B5C8 */
# region @ 801843C4 (4 bytes)
.data 0x801843C4 # address
.data 0x00000004 # size
.data 0x60000000 # 801843C4 => nop
# region @ 80189F54 (4 bytes)
.data 0x80189F54 # address
.data 0x00000004 # size
.data 0x60000000 # 80189F54 => nop
# region @ 801938D8 (4 bytes)
.data 0x801938D8 # address
.data 0x00000004 # size
.data 0x60000000 # 801938D8 => nop
# region @ 801B9D50 (4 bytes)
.data 0x801B9D50 # address
.data 0x00000004 # size
.data 0x4BE526B8 # 801B9D50 => b -0x001AD948 /* 8000C408 */
# region @ 801BA024 (4 bytes)
.data 0x801BA024 # address
.data 0x00000004 # size
.data 0x4BE51064 # 801BA024 => b -0x001AEF9C /* 8000B088 */
# region @ 801C6490 (4 bytes)
.data 0x801C6490 # address
.data 0x00000004 # size
.data 0x389F02FC # 801C6490 => addi r4, r31, 0x02FC
# region @ 801CA810 (4 bytes)
.data 0x801CA810 # address
.data 0x00000004 # size
.data 0x48000010 # 801CA810 => b +0x00000010 /* 801CA820 */
# region @ 8021E9D0 (4 bytes)
.data 0x8021E9D0 # address
.data 0x00000004 # size
.data 0x4BDEDD00 # 8021E9D0 => b -0x00212300 /* 8000C6D0 */
# region @ 80221E90 (4 bytes)
.data 0x80221E90 # address
.data 0x00000004 # size
.data 0x4BDEA850 # 80221E90 => b -0x002157B0 /* 8000C6E0 */
# region @ 8022ACC4 (4 bytes)
.data 0x8022ACC4 # address
.data 0x00000004 # size
.data 0x2C000001 # 8022ACC4 => cmpwi r0, 1
# region @ 8022B4C4 (4 bytes)
.data 0x8022B4C4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022B4C4 => li r4, 0xFFFFFF00
# region @ 8022B4F4 (4 bytes)
.data 0x8022B4F4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022B4F4 => li r4, 0xFFFFFE80
# region @ 8022B524 (4 bytes)
.data 0x8022B524 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022B524 => li r4, 0xFFFFFDB0
# region @ 8022E1C0 (4 bytes)
.data 0x8022E1C0 # address
.data 0x00000004 # size
.data 0x60000000 # 8022E1C0 => nop
# region @ 8022E8F4 (4 bytes)
.data 0x8022E8F4 # address
.data 0x00000004 # size
.data 0x41810630 # 8022E8F4 => bgt +0x00000630 /* 8022EF24 */
# region @ 8022FC18 (4 bytes)
.data 0x8022FC18 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022FC18 => li r4, 0xFFFFFF00
# region @ 8022FC48 (4 bytes)
.data 0x8022FC48 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022FC48 => li r4, 0xFFFFFE80
# region @ 8022FC78 (4 bytes)
.data 0x8022FC78 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022FC78 => li r4, 0xFFFFFDB0
# region @ 80230424 (4 bytes)
.data 0x80230424 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80230424 => li r4, 0xFFFFFF00
# region @ 80230454 (4 bytes)
.data 0x80230454 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80230454 => li r4, 0xFFFFFE80
# region @ 80230484 (4 bytes)
.data 0x80230484 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80230484 => li r4, 0xFFFFFDB0
# region @ 80231A28 (4 bytes)
.data 0x80231A28 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80231A28 => li r4, 0xFFFFFF00
# region @ 80231A58 (4 bytes)
.data 0x80231A58 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80231A58 => li r4, 0xFFFFFE80
# region @ 80231A88 (4 bytes)
.data 0x80231A88 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80231A88 => li r4, 0xFFFFFDB0
# region @ 80232798 (4 bytes)
.data 0x80232798 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80232798 => li r4, 0xFFFFFF00
# region @ 802327C8 (4 bytes)
.data 0x802327C8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802327C8 => li r4, 0xFFFFFE80
# region @ 802327F8 (4 bytes)
.data 0x802327F8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802327F8 => li r4, 0xFFFFFDB0
# region @ 8023308C (4 bytes)
.data 0x8023308C # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023308C => li r4, 0xFFFFFF00
# region @ 802330C4 (4 bytes)
.data 0x802330C4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802330C4 => li r4, 0xFFFFFE80
# region @ 802330FC (4 bytes)
.data 0x802330FC # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802330FC => li r4, 0xFFFFFDB0
# region @ 80235138 (4 bytes)
.data 0x80235138 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80235138 => li r4, 0xFFFFFF00
# region @ 80235168 (4 bytes)
.data 0x80235168 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80235168 => li r4, 0xFFFFFE80
# region @ 80235198 (4 bytes)
.data 0x80235198 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80235198 => li r4, 0xFFFFFDB0
# region @ 80237764 (4 bytes)
.data 0x80237764 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80237764 => li r4, 0xFFFFFF00
# region @ 802377A0 (4 bytes)
.data 0x802377A0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802377A0 => li r4, 0xFFFFFE80
# region @ 802377DC (4 bytes)
.data 0x802377DC # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802377DC => li r4, 0xFFFFFDB0
# region @ 80237F3C (4 bytes)
.data 0x80237F3C # address
.data 0x00000004 # size
.data 0x3880FF00 # 80237F3C => li r4, 0xFFFFFF00
# region @ 80237F6C (4 bytes)
.data 0x80237F6C # address
.data 0x00000004 # size
.data 0x3880FE80 # 80237F6C => li r4, 0xFFFFFE80
# region @ 80237F9C (4 bytes)
.data 0x80237F9C # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80237F9C => li r4, 0xFFFFFDB0
# region @ 80238950 (4 bytes)
.data 0x80238950 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80238950 => li r4, 0xFFFFFF00
# region @ 80238980 (4 bytes)
.data 0x80238980 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80238980 => li r4, 0xFFFFFE80
# region @ 802389B0 (4 bytes)
.data 0x802389B0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802389B0 => li r4, 0xFFFFFDB0
# region @ 80239328 (4 bytes)
.data 0x80239328 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80239328 => li r4, 0xFFFFFF00
# region @ 80239358 (4 bytes)
.data 0x80239358 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80239358 => li r4, 0xFFFFFE80
# region @ 80239388 (4 bytes)
.data 0x80239388 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80239388 => li r4, 0xFFFFFDB0
# region @ 8023CC58 (4 bytes)
.data 0x8023CC58 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023CC58 => li r4, 0xFFFFFF00
# region @ 8023CC88 (4 bytes)
.data 0x8023CC88 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023CC88 => li r4, 0xFFFFFE80
# region @ 8023CCB8 (4 bytes)
.data 0x8023CCB8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023CCB8 => li r4, 0xFFFFFDB0
# region @ 80251C68 (4 bytes)
.data 0x80251C68 # address
.data 0x00000004 # size
.data 0x60000000 # 80251C68 => nop
# region @ 80269B5C (4 bytes)
.data 0x80269B5C # address
.data 0x00000004 # size
.data 0x60000000 # 80269B5C => nop
# region @ 8026F6FC (4 bytes)
.data 0x8026F6FC # address
.data 0x00000004 # size
.data 0x3884AAFA # 8026F6FC => subi r4, r4, 0x5506
# region @ 8026F810 (4 bytes)
.data 0x8026F810 # address
.data 0x00000004 # size
.data 0x3863AAFA # 8026F810 => subi r3, r3, 0x5506
# region @ 8026F898 (4 bytes)
.data 0x8026F898 # address
.data 0x00000004 # size
.data 0x3883AAFA # 8026F898 => subi r4, r3, 0x5506
# region @ 802BD474 (4 bytes)
.data 0x802BD474 # address
.data 0x00000004 # size
.data 0x4BD5050C # 802BD474 => b -0x002AFAF4 /* 8000D980 */
# region @ 802FDD28 (4 bytes)
.data 0x802FDD28 # address
.data 0x00000004 # size
.data 0x2C030001 # 802FDD28 => cmpwi r3, 1
# region @ 8030398C (28 bytes)
.data 0x8030398C # address
.data 0x0000001C # size
.data 0x48000020 # 8030398C => b +0x00000020 /* 803039AC */
.data 0x3863A830 # 80303990 => subi r3, r3, 0x57D0
.data 0x800DB9C4 # 80303994 => lwz r0, [r13 - 0x463C]
.data 0x2C000023 # 80303998 => cmpwi r0, 35
.data 0x40820008 # 8030399C => bne +0x00000008 /* 803039A4 */
.data 0x3863FB28 # 803039A0 => subi r3, r3, 0x04D8
.data 0x4800008C # 803039A4 => b +0x0000008C /* 80303A30 */
# region @ 80303A2C (4 bytes)
.data 0x80303A2C # address
.data 0x00000004 # size
.data 0x4BFFFF64 # 80303A2C => b -0x0000009C /* 80303990 */
# region @ 80337570 (4 bytes)
.data 0x80337570 # address
.data 0x00000004 # size
.data 0x4BCD6430 # 80337570 => b -0x00329BD0 /* 8000D9A0 */
# region @ 80358440 (4 bytes)
.data 0x80358440 # address
.data 0x00000004 # size
.data 0x388001E8 # 80358440 => li r4, 0x01E8
# region @ 80358464 (4 bytes)
.data 0x80358464 # address
.data 0x00000004 # size
.data 0x4BCB5D7D # 80358464 => bl -0x0034A284 /* 8000E1E0 */
# region @ 803584D4 (4 bytes)
.data 0x803584D4 # address
.data 0x00000004 # size
.data 0x388001E8 # 803584D4 => li r4, 0x01E8
# region @ 803584E4 (4 bytes)
.data 0x803584E4 # address
.data 0x00000004 # size
.data 0x4BCB5CFD # 803584E4 => bl -0x0034A304 /* 8000E1E0 */
# region @ 804B8990 (8 bytes)
.data 0x804B8990 # address
.data 0x00000008 # size
.data 0x70808080 # 804B8990 => andi. r0, r4, 0x8080
.data 0x60707070 # 804B8994 => ori r16, r3, 0x7070
# region @ 804CC1E4 (4 bytes)
.data 0x804CC1E4 # address
.data 0x00000004 # size
.data 0x0000001E # 804CC1E4 => .invalid
# region @ 804CC23C (4 bytes)
.data 0x804CC23C # address
.data 0x00000004 # size
.data 0x00000028 # 804CC23C => .invalid
# region @ 804CC268 (4 bytes)
.data 0x804CC268 # address
.data 0x00000004 # size
.data 0x00000032 # 804CC268 => .invalid
# region @ 804CC294 (4 bytes)
.data 0x804CC294 # address
.data 0x00000004 # size
.data 0x0000003C # 804CC294 => .invalid
# region @ 804CC2A4 (4 bytes)
.data 0x804CC2A4 # address
.data 0x00000004 # size
.data 0x0018003C # 804CC2A4 => .invalid
# region @ 804CC4FC (4 bytes)
.data 0x804CC4FC # address
.data 0x00000004 # size
.data 0x00000028 # 804CC4FC => .invalid
# region @ 804D0E58 (4 bytes)
.data 0x804D0E58 # address
.data 0x00000004 # size
.data 0xFF0074EE # 804D0E58 => fsel f24, f0, f14, f19
# region @ 805DAAB4 (4 bytes)
.data 0x805DAAB4 # address
.data 0x00000004 # size
.data 0x435C0000 # 805DAAB4 => bc 26, 28, +0x00000000 /* 805DAAB4 */
# region @ 805DC750 (4 bytes)
.data 0x805DC750 # address
.data 0x00000004 # size
.data 0x46AFC800 # 805DC750 => .invalid sc
# region @ 805DC9F0 (4 bytes)
.data 0x805DC9F0 # address
.data 0x00000004 # size
.data 0x43480000 # 805DC9F0 => bc 26, 8, +0x00000000 /* 805DC9F0 */
# end sentinel
.data 0x00000000 # address
.data 0x00000000 # size
@@ -1,564 +0,0 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
# region @ 8000B088 (88 bytes)
.data 0x8000B088 # address
.data 0x00000058 # size
.data 0x7FA3EB78 # 8000B088 => mr r3, r29
.data 0x38800000 # 8000B08C => li r4, 0x0000
.data 0x481AE725 # 8000B090 => bl +0x001AE724 /* 801B97B4 */
.data 0x7FA3EB78 # 8000B094 => mr r3, r29
.data 0x481AE9F4 # 8000B098 => b +0x001AE9F4 /* 801B9A8C */
.data 0x881F0000 # 8000B09C => lbz r0, [r31]
.data 0x28090001 # 8000B0A0 => cmplwi r9, 1
.data 0x4082000C # 8000B0A4 => bne +0x0000000C /* 8000B0B0 */
.data 0x881F0001 # 8000B0A8 => lbz r0, [r31 + 0x0001]
.data 0x3BFF0002 # 8000B0AC => addi r31, r31, 0x0002
.data 0x481008C4 # 8000B0B0 => b +0x001008C4 /* 8010B974 */
.data 0x39200000 # 8000B0B4 => li r9, 0x0000
.data 0x48100855 # 8000B0B8 => bl +0x00100854 /* 8010B90C */
.data 0x7F43D378 # 8000B0BC => mr r3, r26
.data 0x7F64DB78 # 8000B0C0 => mr r4, r27
.data 0x7F85E378 # 8000B0C4 => mr r5, r28
.data 0x7FA6EB78 # 8000B0C8 => mr r6, r29
.data 0x7FC7F378 # 8000B0CC => mr r7, r30
.data 0x7FE8FB78 # 8000B0D0 => mr r8, r31
.data 0x39200001 # 8000B0D4 => li r9, 0x0001
.data 0x48100835 # 8000B0D8 => bl +0x00100834 /* 8010B90C */
.data 0x48102CC0 # 8000B0DC => b +0x00102CC0 /* 8010DD9C */
# region @ 8000B5C8 (20 bytes)
.data 0x8000B5C8 # address
.data 0x00000014 # size
.data 0x80630098 # 8000B5C8 => lwz r3, [r3 + 0x0098]
.data 0x483D46F5 # 8000B5CC => bl +0x003D46F4 /* 803DFCC0 */
.data 0x807F042C # 8000B5D0 => lwz r3, [r31 + 0x042C]
.data 0x809F0430 # 8000B5D4 => lwz r4, [r31 + 0x0430]
.data 0x481788C0 # 8000B5D8 => b +0x001788C0 /* 80183E98 */
# region @ 8000BBD0 (32 bytes)
.data 0x8000BBD0 # address
.data 0x00000020 # size
.data 0x809F0370 # 8000BBD0 => lwz r4, [r31 + 0x0370]
.data 0x3884FC00 # 8000BBD4 => subi r4, r4, 0x0400
.data 0x909F0370 # 8000BBD8 => stw [r31 + 0x0370], r4
.data 0x807F0014 # 8000BBDC => lwz r3, [r31 + 0x0014]
.data 0x28030000 # 8000BBE0 => cmplwi r3, 0
.data 0x41820008 # 8000BBE4 => beq +0x00000008 /* 8000BBEC */
.data 0x90830060 # 8000BBE8 => stw [r3 + 0x0060], r4
.data 0x4816506C # 8000BBEC => b +0x0016506C /* 80170C58 */
# region @ 8000C3F8 (124 bytes)
.data 0x8000C3F8 # address
.data 0x0000007C # size
.data 0x28040000 # 8000C3F8 => cmplwi r4, 0
.data 0x4D820020 # 8000C3FC => beqlr
.data 0x9421FFF0 # 8000C400 => stwu [r1 - 0x0010], r1
.data 0x481AD3B4 # 8000C404 => b +0x001AD3B4 /* 801B97B8 */
.data 0x9421FFE0 # 8000C408 => stwu [r1 - 0x0020], r1
.data 0x7C0802A6 # 8000C40C => mflr r0
.data 0x90010024 # 8000C410 => stw [r1 + 0x0024], r0
.data 0xBF410008 # 8000C414 => stmw [r1 + 0x0008], r26
.data 0x7C7F1B78 # 8000C418 => mr r31, r3
.data 0x4BFFFFDD # 8000C41C => bl -0x00000024 /* 8000C3F8 */
.data 0x3BC00000 # 8000C420 => li r30, 0x0000
.data 0x3BBF0D04 # 8000C424 => addi r29, r31, 0x0D04
.data 0x837F032C # 8000C428 => lwz r27, [r31 + 0x032C]
.data 0x839D0000 # 8000C42C => lwz r28, [r29]
.data 0x7F83E379 # 8000C430 => mr. r3, r28
.data 0x41820018 # 8000C434 => beq +0x00000018 /* 8000C44C */
.data 0x38800001 # 8000C438 => li r4, 0x0001
.data 0x480FEADD # 8000C43C => bl +0x000FEADC /* 8010AF18 */
.data 0x7F83E378 # 8000C440 => mr r3, r28
.data 0x38800001 # 8000C444 => li r4, 0x0001
.data 0x480FEC4D # 8000C448 => bl +0x000FEC4C /* 8010B094 */
.data 0x3BBD0004 # 8000C44C => addi r29, r29, 0x0004
.data 0x3BDE0001 # 8000C450 => addi r30, r30, 0x0001
.data 0x2C1E000D # 8000C454 => cmpwi r30, 13
.data 0x4180FFD4 # 8000C458 => blt -0x0000002C /* 8000C42C */
.data 0x937F032C # 8000C45C => stw [r31 + 0x032C], r27
.data 0xBB410008 # 8000C460 => lmw r26, [r1 + 0x0008]
.data 0x80010024 # 8000C464 => lwz r0, [r1 + 0x0024]
.data 0x7C0803A6 # 8000C468 => mtlr r0
.data 0x38210020 # 8000C46C => addi r1, r1, 0x0020
.data 0x4E800020 # 8000C470 => blr
# region @ 8000C640 (20 bytes)
.data 0x8000C640 # address
.data 0x00000014 # size
.data 0x54800673 # 8000C640 => rlwinm. r0, r4, 0, 25, 25
.data 0x41820008 # 8000C644 => beq +0x00000008 /* 8000C64C */
.data 0x38800000 # 8000C648 => li r4, 0x0000
.data 0x38040009 # 8000C64C => addi r0, r4, 0x0009
.data 0x4810C694 # 8000C650 => b +0x0010C694 /* 80118CE4 */
# region @ 8000C6D0 (32 bytes)
.data 0x8000C6D0 # address
.data 0x00000020 # size
.data 0x38000001 # 8000C6D0 => li r0, 0x0001
.data 0x901D0054 # 8000C6D4 => stw [r29 + 0x0054], r0
.data 0x807D0024 # 8000C6D8 => lwz r3, [r29 + 0x0024]
.data 0x482109C0 # 8000C6DC => b +0x002109C0 /* 8021D09C */
.data 0x38000001 # 8000C6E0 => li r0, 0x0001
.data 0x901F0378 # 8000C6E4 => stw [r31 + 0x0378], r0
.data 0x807F0024 # 8000C6E8 => lwz r3, [r31 + 0x0024]
.data 0x48165AA0 # 8000C6EC => b +0x00165AA0 /* 8017218C */
# region @ 8000C8A0 (20 bytes)
.data 0x8000C8A0 # address
.data 0x00000014 # size
.data 0x1C00000A # 8000C8A0 => mulli r0, r0, 10
.data 0x57E407BD # 8000C8A4 => rlwinm. r4, r31, 0, 30, 30
.data 0x41820008 # 8000C8A8 => beq +0x00000008 /* 8000C8B0 */
.data 0x7FA00734 # 8000C8AC => extsh r0, r29
.data 0x48105DB8 # 8000C8B0 => b +0x00105DB8 /* 80112668 */
# region @ 8000C8C0 (16 bytes)
.data 0x8000C8C0 # address
.data 0x00000010 # size
.data 0x7000000F # 8000C8C0 => andi. r0, r0, 0x000F
.data 0x7000004F # 8000C8C4 => andi. r0, r0, 0x004F
.data 0x2C000004 # 8000C8C8 => cmpwi r0, 4
.data 0x4E800020 # 8000C8CC => blr
# region @ 8000D980 (20 bytes)
.data 0x8000D980 # address
.data 0x00000014 # size
.data 0x807C0000 # 8000D980 => lwz r3, [r28]
.data 0x2C030013 # 8000D984 => cmpwi r3, 19
.data 0x40820008 # 8000D988 => bne +0x00000008 /* 8000D990 */
.data 0x38600002 # 8000D98C => li r3, 0x0002
.data 0x482ADB24 # 8000D990 => b +0x002ADB24 /* 802BB4B4 */
# region @ 8000D9A0 (24 bytes)
.data 0x8000D9A0 # address
.data 0x00000018 # size
.data 0xC042FC78 # 8000D9A0 => lfs f2, [r2 - 0x0388]
.data 0x807E0030 # 8000D9A4 => lwz r3, [r30 + 0x0030]
.data 0x70630020 # 8000D9A8 => andi. r3, r3, 0x0020
.data 0x41820008 # 8000D9AC => beq +0x00000008 /* 8000D9B4 */
.data 0xC042FC90 # 8000D9B0 => lfs f2, [r2 - 0x0370]
.data 0x483276B0 # 8000D9B4 => b +0x003276B0 /* 80335064 */
# region @ 8000E1E0 (28 bytes)
.data 0x8000E1E0 # address
.data 0x0000001C # size
.data 0x7FC802A6 # 8000E1E0 => mflr r30
.data 0x38A00000 # 8000E1E4 => li r5, 0x0000
.data 0x38C0001E # 8000E1E8 => li r6, 0x001E
.data 0x38E00040 # 8000E1EC => li r7, 0x0040
.data 0x480782B1 # 8000E1F0 => bl +0x000782B0 /* 800864A0 */
.data 0x7FC803A6 # 8000E1F4 => mtlr r30
.data 0x4E800020 # 8000E1F8 => blr
# region @ 8001306C (4 bytes)
.data 0x8001306C # address
.data 0x00000004 # size
.data 0x4BFFFCC0 # 8001306C => b -0x00000340 /* 80012D2C */
# region @ 800142DC (4 bytes)
.data 0x800142DC # address
.data 0x00000004 # size
.data 0x4BFF85E5 # 800142DC => bl -0x00007A1C /* 8000C8C0 */
# region @ 80015D04 (4 bytes)
.data 0x80015D04 # address
.data 0x00000004 # size
.data 0x4BFF6BC1 # 80015D04 => bl -0x00009440 /* 8000C8C4 */
# region @ 80091528 (8 bytes)
.data 0x80091528 # address
.data 0x00000008 # size
.data 0x4800024D # 80091528 => bl +0x0000024C /* 80091774 */
.data 0xB3C3032C # 8009152C => sth [r3 + 0x032C], r30
# region @ 800BC750 (4 bytes)
.data 0x800BC750 # address
.data 0x00000004 # size
.data 0x48000010 # 800BC750 => b +0x00000010 /* 800BC760 */
# region @ 80101C14 (4 bytes)
.data 0x80101C14 # address
.data 0x00000004 # size
.data 0x60000000 # 80101C14 => nop
# region @ 80104B48 (4 bytes)
.data 0x80104B48 # address
.data 0x00000004 # size
.data 0x4182000C # 80104B48 => beq +0x0000000C /* 80104B54 */
# region @ 80107478 (4 bytes)
.data 0x80107478 # address
.data 0x00000004 # size
.data 0x4800000C # 80107478 => b +0x0000000C /* 80107484 */
# region @ 8010748C (4 bytes)
.data 0x8010748C # address
.data 0x00000004 # size
.data 0x7C030378 # 8010748C => mr r3, r0
# region @ 8010B970 (4 bytes)
.data 0x8010B970 # address
.data 0x00000004 # size
.data 0x4BEFF72C # 8010B970 => b -0x001008D4 /* 8000B09C */
# region @ 8010DD98 (4 bytes)
.data 0x8010DD98 # address
.data 0x00000004 # size
.data 0x4BEFD31C # 8010DD98 => b -0x00102CE4 /* 8000B0B4 */
# region @ 80112664 (4 bytes)
.data 0x80112664 # address
.data 0x00000004 # size
.data 0x4BEFA23C # 80112664 => b -0x00105DC4 /* 8000C8A0 */
# region @ 80114378 (4 bytes)
.data 0x80114378 # address
.data 0x00000004 # size
.data 0x38000012 # 80114378 => li r0, 0x0012
# region @ 801185B0 (4 bytes)
.data 0x801185B0 # address
.data 0x00000004 # size
.data 0x88040016 # 801185B0 => lbz r0, [r4 + 0x0016]
# region @ 801185BC (4 bytes)
.data 0x801185BC # address
.data 0x00000004 # size
.data 0x88040017 # 801185BC => lbz r0, [r4 + 0x0017]
# region @ 80118CE0 (4 bytes)
.data 0x80118CE0 # address
.data 0x00000004 # size
.data 0x4BEF3960 # 80118CE0 => b -0x0010C6A0 /* 8000C640 */
# region @ 8011CA90 (12 bytes)
.data 0x8011CA90 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CA90 => mr r3, r0
.data 0x3863FFFF # 8011CA94 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CA98 => b -0x00000018 /* 8011CA80 */
# region @ 8011CB4C (12 bytes)
.data 0x8011CB4C # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CB4C => mr r3, r0
.data 0x3863FFFF # 8011CB50 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CB54 => b -0x00000018 /* 8011CB3C */
# region @ 8011CB9C (12 bytes)
.data 0x8011CB9C # address
.data 0x0000000C # size
.data 0x7C040378 # 8011CB9C => mr r4, r0
.data 0x3884FFFF # 8011CBA0 => subi r4, r4, 0x0001
.data 0x4BFFFFE8 # 8011CBA4 => b -0x00000018 /* 8011CB8C */
# region @ 80166324 (8 bytes)
.data 0x80166324 # address
.data 0x00000008 # size
.data 0x3C604005 # 80166324 => lis r3, 0x4005
.data 0x4800009C # 80166328 => b +0x0000009C /* 801663C4 */
# region @ 801663C0 (4 bytes)
.data 0x801663C0 # address
.data 0x00000004 # size
.data 0x4800001C # 801663C0 => b +0x0000001C /* 801663DC */
# region @ 80170C54 (4 bytes)
.data 0x80170C54 # address
.data 0x00000004 # size
.data 0x4BE9AF7C # 80170C54 => b -0x00165084 /* 8000BBD0 */
# region @ 80170C74 (4 bytes)
.data 0x80170C74 # address
.data 0x00000004 # size
.data 0x60800420 # 80170C74 => ori r0, r4, 0x0420
# region @ 80172188 (4 bytes)
.data 0x80172188 # address
.data 0x00000004 # size
.data 0x4BE9A558 # 80172188 => b -0x00165AA8 /* 8000C6E0 */
# region @ 80183E94 (4 bytes)
.data 0x80183E94 # address
.data 0x00000004 # size
.data 0x4BE87734 # 80183E94 => b -0x001788CC /* 8000B5C8 */
# region @ 80183ED4 (4 bytes)
.data 0x80183ED4 # address
.data 0x00000004 # size
.data 0x60000000 # 80183ED4 => nop
# region @ 80189A54 (4 bytes)
.data 0x80189A54 # address
.data 0x00000004 # size
.data 0x60000000 # 80189A54 => nop
# region @ 801933DC (4 bytes)
.data 0x801933DC # address
.data 0x00000004 # size
.data 0x60000000 # 801933DC => nop
# region @ 801B97B4 (4 bytes)
.data 0x801B97B4 # address
.data 0x00000004 # size
.data 0x4BE52C54 # 801B97B4 => b -0x001AD3AC /* 8000C408 */
# region @ 801B9A88 (4 bytes)
.data 0x801B9A88 # address
.data 0x00000004 # size
.data 0x4BE51600 # 801B9A88 => b -0x001AEA00 /* 8000B088 */
# region @ 801C5EA4 (4 bytes)
.data 0x801C5EA4 # address
.data 0x00000004 # size
.data 0x389F02FC # 801C5EA4 => addi r4, r31, 0x02FC
# region @ 801CA1F4 (4 bytes)
.data 0x801CA1F4 # address
.data 0x00000004 # size
.data 0x48000010 # 801CA1F4 => b +0x00000010 /* 801CA204 */
# region @ 8021D098 (4 bytes)
.data 0x8021D098 # address
.data 0x00000004 # size
.data 0x4BDEF638 # 8021D098 => b -0x002109C8 /* 8000C6D0 */
# region @ 80229354 (4 bytes)
.data 0x80229354 # address
.data 0x00000004 # size
.data 0x2C000001 # 80229354 => cmpwi r0, 1
# region @ 80229B54 (4 bytes)
.data 0x80229B54 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80229B54 => li r4, 0xFFFFFF00
# region @ 80229B84 (4 bytes)
.data 0x80229B84 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80229B84 => li r4, 0xFFFFFE80
# region @ 80229BB4 (4 bytes)
.data 0x80229BB4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80229BB4 => li r4, 0xFFFFFDB0
# region @ 8022C850 (4 bytes)
.data 0x8022C850 # address
.data 0x00000004 # size
.data 0x60000000 # 8022C850 => nop
# region @ 8022CF84 (4 bytes)
.data 0x8022CF84 # address
.data 0x00000004 # size
.data 0x41810630 # 8022CF84 => bgt +0x00000630 /* 8022D5B4 */
# region @ 8022D278 (4 bytes)
.data 0x8022D278 # address
.data 0x00000004 # size
.data 0x4181033C # 8022D278 => bgt +0x0000033C /* 8022D5B4 */
# region @ 8022D36C (4 bytes)
.data 0x8022D36C # address
.data 0x00000004 # size
.data 0x41810248 # 8022D36C => bgt +0x00000248 /* 8022D5B4 */
# region @ 8022E2A8 (4 bytes)
.data 0x8022E2A8 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022E2A8 => li r4, 0xFFFFFF00
# region @ 8022E2D8 (4 bytes)
.data 0x8022E2D8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022E2D8 => li r4, 0xFFFFFE80
# region @ 8022E308 (4 bytes)
.data 0x8022E308 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022E308 => li r4, 0xFFFFFDB0
# region @ 8022EAB4 (4 bytes)
.data 0x8022EAB4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022EAB4 => li r4, 0xFFFFFF00
# region @ 8022EAE4 (4 bytes)
.data 0x8022EAE4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022EAE4 => li r4, 0xFFFFFE80
# region @ 8022EB14 (4 bytes)
.data 0x8022EB14 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022EB14 => li r4, 0xFFFFFDB0
# region @ 802300B8 (4 bytes)
.data 0x802300B8 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802300B8 => li r4, 0xFFFFFF00
# region @ 802300E8 (4 bytes)
.data 0x802300E8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802300E8 => li r4, 0xFFFFFE80
# region @ 80230118 (4 bytes)
.data 0x80230118 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80230118 => li r4, 0xFFFFFDB0
# region @ 80230E08 (4 bytes)
.data 0x80230E08 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80230E08 => li r4, 0xFFFFFF00
# region @ 80230E38 (4 bytes)
.data 0x80230E38 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80230E38 => li r4, 0xFFFFFE80
# region @ 80230E68 (4 bytes)
.data 0x80230E68 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80230E68 => li r4, 0xFFFFFDB0
# region @ 802316FC (4 bytes)
.data 0x802316FC # address
.data 0x00000004 # size
.data 0x3880FF00 # 802316FC => li r4, 0xFFFFFF00
# region @ 80231734 (4 bytes)
.data 0x80231734 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80231734 => li r4, 0xFFFFFE80
# region @ 8023176C (4 bytes)
.data 0x8023176C # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023176C => li r4, 0xFFFFFDB0
# region @ 802337A8 (4 bytes)
.data 0x802337A8 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802337A8 => li r4, 0xFFFFFF00
# region @ 802337D8 (4 bytes)
.data 0x802337D8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802337D8 => li r4, 0xFFFFFE80
# region @ 80233808 (4 bytes)
.data 0x80233808 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80233808 => li r4, 0xFFFFFDB0
# region @ 80235DD4 (4 bytes)
.data 0x80235DD4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80235DD4 => li r4, 0xFFFFFF00
# region @ 80235E10 (4 bytes)
.data 0x80235E10 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80235E10 => li r4, 0xFFFFFE80
# region @ 80235E4C (4 bytes)
.data 0x80235E4C # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80235E4C => li r4, 0xFFFFFDB0
# region @ 802365AC (4 bytes)
.data 0x802365AC # address
.data 0x00000004 # size
.data 0x3880FF00 # 802365AC => li r4, 0xFFFFFF00
# region @ 802365DC (4 bytes)
.data 0x802365DC # address
.data 0x00000004 # size
.data 0x3880FE80 # 802365DC => li r4, 0xFFFFFE80
# region @ 8023660C (4 bytes)
.data 0x8023660C # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023660C => li r4, 0xFFFFFDB0
# region @ 80236FC0 (4 bytes)
.data 0x80236FC0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80236FC0 => li r4, 0xFFFFFF00
# region @ 80236FF0 (4 bytes)
.data 0x80236FF0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80236FF0 => li r4, 0xFFFFFE80
# region @ 80237020 (4 bytes)
.data 0x80237020 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80237020 => li r4, 0xFFFFFDB0
# region @ 80237998 (4 bytes)
.data 0x80237998 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80237998 => li r4, 0xFFFFFF00
# region @ 802379C8 (4 bytes)
.data 0x802379C8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802379C8 => li r4, 0xFFFFFE80
# region @ 802379F8 (4 bytes)
.data 0x802379F8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802379F8 => li r4, 0xFFFFFDB0
# region @ 8023B2C8 (4 bytes)
.data 0x8023B2C8 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023B2C8 => li r4, 0xFFFFFF00
# region @ 8023B2F8 (4 bytes)
.data 0x8023B2F8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023B2F8 => li r4, 0xFFFFFE80
# region @ 8023B328 (4 bytes)
.data 0x8023B328 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023B328 => li r4, 0xFFFFFDB0
# region @ 80250264 (4 bytes)
.data 0x80250264 # address
.data 0x00000004 # size
.data 0x60000000 # 80250264 => nop
# region @ 80267DDC (4 bytes)
.data 0x80267DDC # address
.data 0x00000004 # size
.data 0x60000000 # 80267DDC => nop
# region @ 8026DA74 (4 bytes)
.data 0x8026DA74 # address
.data 0x00000004 # size
.data 0x3884AAFA # 8026DA74 => subi r4, r4, 0x5506
# region @ 8026DB88 (4 bytes)
.data 0x8026DB88 # address
.data 0x00000004 # size
.data 0x3863AAFA # 8026DB88 => subi r3, r3, 0x5506
# region @ 8026DC10 (4 bytes)
.data 0x8026DC10 # address
.data 0x00000004 # size
.data 0x3883AAFA # 8026DC10 => subi r4, r3, 0x5506
# region @ 802BB4B0 (4 bytes)
.data 0x802BB4B0 # address
.data 0x00000004 # size
.data 0x4BD524D0 # 802BB4B0 => b -0x002ADB30 /* 8000D980 */
# region @ 802FB99C (4 bytes)
.data 0x802FB99C # address
.data 0x00000004 # size
.data 0x2C030001 # 802FB99C => cmpwi r3, 1
# region @ 80301600 (28 bytes)
.data 0x80301600 # address
.data 0x0000001C # size
.data 0x48000020 # 80301600 => b +0x00000020 /* 80301620 */
.data 0x3863A830 # 80301604 => subi r3, r3, 0x57D0
.data 0x800DB98C # 80301608 => lwz r0, [r13 - 0x4674]
.data 0x2C000023 # 8030160C => cmpwi r0, 35
.data 0x40820008 # 80301610 => bne +0x00000008 /* 80301618 */
.data 0x3863FB28 # 80301614 => subi r3, r3, 0x04D8
.data 0x4800008C # 80301618 => b +0x0000008C /* 803016A4 */
# region @ 803016A0 (4 bytes)
.data 0x803016A0 # address
.data 0x00000004 # size
.data 0x4BFFFF64 # 803016A0 => b -0x0000009C /* 80301604 */
# region @ 80335060 (4 bytes)
.data 0x80335060 # address
.data 0x00000004 # size
.data 0x4BCD8940 # 80335060 => b -0x003276C0 /* 8000D9A0 */
# region @ 80355960 (4 bytes)
.data 0x80355960 # address
.data 0x00000004 # size
.data 0x388001E8 # 80355960 => li r4, 0x01E8
# region @ 80355984 (4 bytes)
.data 0x80355984 # address
.data 0x00000004 # size
.data 0x4BCB885D # 80355984 => bl -0x003477A4 /* 8000E1E0 */
# region @ 803559F4 (4 bytes)
.data 0x803559F4 # address
.data 0x00000004 # size
.data 0x388001E8 # 803559F4 => li r4, 0x01E8
# region @ 80355A04 (4 bytes)
.data 0x80355A04 # address
.data 0x00000004 # size
.data 0x4BCB87DD # 80355A04 => bl -0x00347824 /* 8000E1E0 */
# region @ 804B3738 (8 bytes)
.data 0x804B3738 # address
.data 0x00000008 # size
.data 0x70808080 # 804B3738 => andi. r0, r4, 0x8080
.data 0x60707070 # 804B373C => ori r16, r3, 0x7070
# region @ 804C6EE4 (4 bytes)
.data 0x804C6EE4 # address
.data 0x00000004 # size
.data 0x0000001E # 804C6EE4 => .invalid
# region @ 804C6F3C (4 bytes)
.data 0x804C6F3C # address
.data 0x00000004 # size
.data 0x00000028 # 804C6F3C => .invalid
# region @ 804C6F68 (4 bytes)
.data 0x804C6F68 # address
.data 0x00000004 # size
.data 0x00000032 # 804C6F68 => .invalid
# region @ 804C6F94 (4 bytes)
.data 0x804C6F94 # address
.data 0x00000004 # size
.data 0x0000003C # 804C6F94 => .invalid
# region @ 804C6FA4 (4 bytes)
.data 0x804C6FA4 # address
.data 0x00000004 # size
.data 0x0018003C # 804C6FA4 => .invalid
# region @ 804C71FC (4 bytes)
.data 0x804C71FC # address
.data 0x00000004 # size
.data 0x00000028 # 804C71FC => .invalid
# region @ 804CBB40 (4 bytes)
.data 0x804CBB40 # address
.data 0x00000004 # size
.data 0xFF0074EE # 804CBB40 => fsel f24, f0, f14, f19
# region @ 805C996C (4 bytes)
.data 0x805C996C # address
.data 0x00000004 # size
.data 0x435C0000 # 805C996C => bc 26, 28, +0x00000000 /* 805C996C */
# region @ 805CB608 (4 bytes)
.data 0x805CB608 # address
.data 0x00000004 # size
.data 0x46AFC800 # 805CB608 => .invalid sc
# region @ 805CB8A8 (4 bytes)
.data 0x805CB8A8 # address
.data 0x00000004 # size
.data 0x43480000 # 805CB8A8 => bc 26, 8, +0x00000000 /* 805CB8A8 */
# end sentinel
.data 0x00000000 # address
.data 0x00000000 # size
@@ -1,552 +0,0 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
# region @ 8000B088 (88 bytes)
.data 0x8000B088 # address
.data 0x00000058 # size
.data 0x7FA3EB78 # 8000B088 => mr r3, r29
.data 0x38800000 # 8000B08C => li r4, 0x0000
.data 0x481AEB91 # 8000B090 => bl +0x001AEB90 /* 801B9C20 */
.data 0x7FA3EB78 # 8000B094 => mr r3, r29
.data 0x481AEE60 # 8000B098 => b +0x001AEE60 /* 801B9EF8 */
.data 0x881F0000 # 8000B09C => lbz r0, [r31]
.data 0x28090001 # 8000B0A0 => cmplwi r9, 1
.data 0x4082000C # 8000B0A4 => bne +0x0000000C /* 8000B0B0 */
.data 0x881F0001 # 8000B0A8 => lbz r0, [r31 + 0x0001]
.data 0x3BFF0002 # 8000B0AC => addi r31, r31, 0x0002
.data 0x48100AC4 # 8000B0B0 => b +0x00100AC4 /* 8010BB74 */
.data 0x39200000 # 8000B0B4 => li r9, 0x0000
.data 0x48100A55 # 8000B0B8 => bl +0x00100A54 /* 8010BB0C */
.data 0x7F43D378 # 8000B0BC => mr r3, r26
.data 0x7F64DB78 # 8000B0C0 => mr r4, r27
.data 0x7F85E378 # 8000B0C4 => mr r5, r28
.data 0x7FA6EB78 # 8000B0C8 => mr r6, r29
.data 0x7FC7F378 # 8000B0CC => mr r7, r30
.data 0x7FE8FB78 # 8000B0D0 => mr r8, r31
.data 0x39200001 # 8000B0D4 => li r9, 0x0001
.data 0x48100A35 # 8000B0D8 => bl +0x00100A34 /* 8010BB0C */
.data 0x48102EC0 # 8000B0DC => b +0x00102EC0 /* 8010DF9C */
# region @ 8000B5C8 (20 bytes)
.data 0x8000B5C8 # address
.data 0x00000014 # size
.data 0x80630098 # 8000B5C8 => lwz r3, [r3 + 0x0098]
.data 0x483D70D1 # 8000B5CC => bl +0x003D70D0 /* 803E269C */
.data 0x807F042C # 8000B5D0 => lwz r3, [r31 + 0x042C]
.data 0x809F0430 # 8000B5D4 => lwz r4, [r31 + 0x0430]
.data 0x48178C88 # 8000B5D8 => b +0x00178C88 /* 80184260 */
# region @ 8000BBD0 (32 bytes)
.data 0x8000BBD0 # address
.data 0x00000020 # size
.data 0x809F0370 # 8000BBD0 => lwz r4, [r31 + 0x0370]
.data 0x3884FC00 # 8000BBD4 => subi r4, r4, 0x0400
.data 0x909F0370 # 8000BBD8 => stw [r31 + 0x0370], r4
.data 0x807F0014 # 8000BBDC => lwz r3, [r31 + 0x0014]
.data 0x28030000 # 8000BBE0 => cmplwi r3, 0
.data 0x41820008 # 8000BBE4 => beq +0x00000008 /* 8000BBEC */
.data 0x90830060 # 8000BBE8 => stw [r3 + 0x0060], r4
.data 0x48165420 # 8000BBEC => b +0x00165420 /* 8017100C */
# region @ 8000C3F8 (124 bytes)
.data 0x8000C3F8 # address
.data 0x0000007C # size
.data 0x28040000 # 8000C3F8 => cmplwi r4, 0
.data 0x4D820020 # 8000C3FC => beqlr
.data 0x9421FFF0 # 8000C400 => stwu [r1 - 0x0010], r1
.data 0x481AD820 # 8000C404 => b +0x001AD820 /* 801B9C24 */
.data 0x9421FFE0 # 8000C408 => stwu [r1 - 0x0020], r1
.data 0x7C0802A6 # 8000C40C => mflr r0
.data 0x90010024 # 8000C410 => stw [r1 + 0x0024], r0
.data 0xBF410008 # 8000C414 => stmw [r1 + 0x0008], r26
.data 0x7C7F1B78 # 8000C418 => mr r31, r3
.data 0x4BFFFFDD # 8000C41C => bl -0x00000024 /* 8000C3F8 */
.data 0x3BC00000 # 8000C420 => li r30, 0x0000
.data 0x3BBF0D04 # 8000C424 => addi r29, r31, 0x0D04
.data 0x837F032C # 8000C428 => lwz r27, [r31 + 0x032C]
.data 0x839D0000 # 8000C42C => lwz r28, [r29]
.data 0x7F83E379 # 8000C430 => mr. r3, r28
.data 0x41820018 # 8000C434 => beq +0x00000018 /* 8000C44C */
.data 0x38800001 # 8000C438 => li r4, 0x0001
.data 0x480FECDD # 8000C43C => bl +0x000FECDC /* 8010B118 */
.data 0x7F83E378 # 8000C440 => mr r3, r28
.data 0x38800001 # 8000C444 => li r4, 0x0001
.data 0x480FEE4D # 8000C448 => bl +0x000FEE4C /* 8010B294 */
.data 0x3BBD0004 # 8000C44C => addi r29, r29, 0x0004
.data 0x3BDE0001 # 8000C450 => addi r30, r30, 0x0001
.data 0x2C1E000D # 8000C454 => cmpwi r30, 13
.data 0x4180FFD4 # 8000C458 => blt -0x0000002C /* 8000C42C */
.data 0x937F032C # 8000C45C => stw [r31 + 0x032C], r27
.data 0xBB410008 # 8000C460 => lmw r26, [r1 + 0x0008]
.data 0x80010024 # 8000C464 => lwz r0, [r1 + 0x0024]
.data 0x7C0803A6 # 8000C468 => mtlr r0
.data 0x38210020 # 8000C46C => addi r1, r1, 0x0020
.data 0x4E800020 # 8000C470 => blr
# region @ 8000C640 (20 bytes)
.data 0x8000C640 # address
.data 0x00000014 # size
.data 0x54800673 # 8000C640 => rlwinm. r0, r4, 0, 25, 25
.data 0x41820008 # 8000C644 => beq +0x00000008 /* 8000C64C */
.data 0x38800000 # 8000C648 => li r4, 0x0000
.data 0x38040009 # 8000C64C => addi r0, r4, 0x0009
.data 0x4810C8B0 # 8000C650 => b +0x0010C8B0 /* 80118F00 */
# region @ 8000C6D0 (32 bytes)
.data 0x8000C6D0 # address
.data 0x00000020 # size
.data 0x38000001 # 8000C6D0 => li r0, 0x0001
.data 0x901D0054 # 8000C6D4 => stw [r29 + 0x0054], r0
.data 0x807D0024 # 8000C6D8 => lwz r3, [r29 + 0x0024]
.data 0x48211324 # 8000C6DC => b +0x00211324 /* 8021DA00 */
.data 0x38000001 # 8000C6E0 => li r0, 0x0001
.data 0x901F0378 # 8000C6E4 => stw [r31 + 0x0378], r0
.data 0x807F0024 # 8000C6E8 => lwz r3, [r31 + 0x0024]
.data 0x482147D4 # 8000C6EC => b +0x002147D4 /* 80220EC0 */
# region @ 8000C8A0 (20 bytes)
.data 0x8000C8A0 # address
.data 0x00000014 # size
.data 0x1C00000A # 8000C8A0 => mulli r0, r0, 10
.data 0x57E407BD # 8000C8A4 => rlwinm. r4, r31, 0, 30, 30
.data 0x41820008 # 8000C8A8 => beq +0x00000008 /* 8000C8B0 */
.data 0x7FA00734 # 8000C8AC => extsh r0, r29
.data 0x48105FB8 # 8000C8B0 => b +0x00105FB8 /* 80112868 */
# region @ 8000C8C0 (16 bytes)
.data 0x8000C8C0 # address
.data 0x00000010 # size
.data 0x7000000F # 8000C8C0 => andi. r0, r0, 0x000F
.data 0x7000004F # 8000C8C4 => andi. r0, r0, 0x004F
.data 0x2C000004 # 8000C8C8 => cmpwi r0, 4
.data 0x4E800020 # 8000C8CC => blr
# region @ 8000D980 (20 bytes)
.data 0x8000D980 # address
.data 0x00000014 # size
.data 0x807C0000 # 8000D980 => lwz r3, [r28]
.data 0x2C030013 # 8000D984 => cmpwi r3, 19
.data 0x40820008 # 8000D988 => bne +0x00000008 /* 8000D990 */
.data 0x38600002 # 8000D98C => li r3, 0x0002
.data 0x482AEA54 # 8000D990 => b +0x002AEA54 /* 802BC3E4 */
# region @ 8000D9A0 (24 bytes)
.data 0x8000D9A0 # address
.data 0x00000018 # size
.data 0xC042FC80 # 8000D9A0 => lfs f2, [r2 - 0x0380]
.data 0x807E0030 # 8000D9A4 => lwz r3, [r30 + 0x0030]
.data 0x70630020 # 8000D9A8 => andi. r3, r3, 0x0020
.data 0x41820008 # 8000D9AC => beq +0x00000008 /* 8000D9B4 */
.data 0xC042FC98 # 8000D9B0 => lfs f2, [r2 - 0x0368]
.data 0x4832871C # 8000D9B4 => b +0x0032871C /* 803360D0 */
# region @ 8000E1E0 (28 bytes)
.data 0x8000E1E0 # address
.data 0x0000001C # size
.data 0x7FC802A6 # 8000E1E0 => mflr r30
.data 0x38A00000 # 8000E1E4 => li r5, 0x0000
.data 0x38C0001E # 8000E1E8 => li r6, 0x001E
.data 0x38E00040 # 8000E1EC => li r7, 0x0040
.data 0x4807859D # 8000E1F0 => bl +0x0007859C /* 8008678C */
.data 0x7FC803A6 # 8000E1F4 => mtlr r30
.data 0x4E800020 # 8000E1F8 => blr
# region @ 8001309C (4 bytes)
.data 0x8001309C # address
.data 0x00000004 # size
.data 0x4BFFFCC0 # 8001309C => b -0x00000340 /* 80012D5C */
# region @ 8001430C (4 bytes)
.data 0x8001430C # address
.data 0x00000004 # size
.data 0x4BFF85B5 # 8001430C => bl -0x00007A4C /* 8000C8C0 */
# region @ 80015D34 (4 bytes)
.data 0x80015D34 # address
.data 0x00000004 # size
.data 0x4BFF6B91 # 80015D34 => bl -0x00009470 /* 8000C8C4 */
# region @ 80091814 (8 bytes)
.data 0x80091814 # address
.data 0x00000008 # size
.data 0x4800024D # 80091814 => bl +0x0000024C /* 80091A60 */
.data 0xB3C3032C # 80091818 => sth [r3 + 0x032C], r30
# region @ 800BCA58 (4 bytes)
.data 0x800BCA58 # address
.data 0x00000004 # size
.data 0x48000010 # 800BCA58 => b +0x00000010 /* 800BCA68 */
# region @ 80104D24 (4 bytes)
.data 0x80104D24 # address
.data 0x00000004 # size
.data 0x4182000C # 80104D24 => beq +0x0000000C /* 80104D30 */
# region @ 80107654 (4 bytes)
.data 0x80107654 # address
.data 0x00000004 # size
.data 0x4800000C # 80107654 => b +0x0000000C /* 80107660 */
# region @ 80107668 (4 bytes)
.data 0x80107668 # address
.data 0x00000004 # size
.data 0x7C030378 # 80107668 => mr r3, r0
# region @ 8010BB70 (4 bytes)
.data 0x8010BB70 # address
.data 0x00000004 # size
.data 0x4BEFF52C # 8010BB70 => b -0x00100AD4 /* 8000B09C */
# region @ 8010DF98 (4 bytes)
.data 0x8010DF98 # address
.data 0x00000004 # size
.data 0x4BEFD11C # 8010DF98 => b -0x00102EE4 /* 8000B0B4 */
# region @ 80112864 (4 bytes)
.data 0x80112864 # address
.data 0x00000004 # size
.data 0x4BEFA03C # 80112864 => b -0x00105FC4 /* 8000C8A0 */
# region @ 8011458C (4 bytes)
.data 0x8011458C # address
.data 0x00000004 # size
.data 0x38000012 # 8011458C => li r0, 0x0012
# region @ 801187CC (4 bytes)
.data 0x801187CC # address
.data 0x00000004 # size
.data 0x88040016 # 801187CC => lbz r0, [r4 + 0x0016]
# region @ 801187D8 (4 bytes)
.data 0x801187D8 # address
.data 0x00000004 # size
.data 0x88040017 # 801187D8 => lbz r0, [r4 + 0x0017]
# region @ 80118EFC (4 bytes)
.data 0x80118EFC # address
.data 0x00000004 # size
.data 0x4BEF3744 # 80118EFC => b -0x0010C8BC /* 8000C640 */
# region @ 8011CCD4 (12 bytes)
.data 0x8011CCD4 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CCD4 => mr r3, r0
.data 0x3863FFFF # 8011CCD8 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CCDC => b -0x00000018 /* 8011CCC4 */
# region @ 8011CD90 (12 bytes)
.data 0x8011CD90 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CD90 => mr r3, r0
.data 0x3863FFFF # 8011CD94 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CD98 => b -0x00000018 /* 8011CD80 */
# region @ 8011CDE0 (12 bytes)
.data 0x8011CDE0 # address
.data 0x0000000C # size
.data 0x7C040378 # 8011CDE0 => mr r4, r0
.data 0x3884FFFF # 8011CDE4 => subi r4, r4, 0x0001
.data 0x4BFFFFE8 # 8011CDE8 => b -0x00000018 /* 8011CDD0 */
# region @ 801666D8 (8 bytes)
.data 0x801666D8 # address
.data 0x00000008 # size
.data 0x3C604005 # 801666D8 => lis r3, 0x4005
.data 0x4800009C # 801666DC => b +0x0000009C /* 80166778 */
# region @ 80166774 (4 bytes)
.data 0x80166774 # address
.data 0x00000004 # size
.data 0x4800001C # 80166774 => b +0x0000001C /* 80166790 */
# region @ 80171008 (4 bytes)
.data 0x80171008 # address
.data 0x00000004 # size
.data 0x4BE9ABC8 # 80171008 => b -0x00165438 /* 8000BBD0 */
# region @ 80171028 (4 bytes)
.data 0x80171028 # address
.data 0x00000004 # size
.data 0x60800420 # 80171028 => ori r0, r4, 0x0420
# region @ 8018425C (4 bytes)
.data 0x8018425C # address
.data 0x00000004 # size
.data 0x4BE8736C # 8018425C => b -0x00178C94 /* 8000B5C8 */
# region @ 8018429C (4 bytes)
.data 0x8018429C # address
.data 0x00000004 # size
.data 0x60000000 # 8018429C => nop
# region @ 80189E2C (4 bytes)
.data 0x80189E2C # address
.data 0x00000004 # size
.data 0x60000000 # 80189E2C => nop
# region @ 801937B0 (4 bytes)
.data 0x801937B0 # address
.data 0x00000004 # size
.data 0x60000000 # 801937B0 => nop
# region @ 801B9C20 (4 bytes)
.data 0x801B9C20 # address
.data 0x00000004 # size
.data 0x4BE527E8 # 801B9C20 => b -0x001AD818 /* 8000C408 */
# region @ 801B9EF4 (4 bytes)
.data 0x801B9EF4 # address
.data 0x00000004 # size
.data 0x4BE51194 # 801B9EF4 => b -0x001AEE6C /* 8000B088 */
# region @ 801C6360 (4 bytes)
.data 0x801C6360 # address
.data 0x00000004 # size
.data 0x389F02FC # 801C6360 => addi r4, r31, 0x02FC
# region @ 801CA6E0 (4 bytes)
.data 0x801CA6E0 # address
.data 0x00000004 # size
.data 0x48000010 # 801CA6E0 => b +0x00000010 /* 801CA6F0 */
# region @ 8021D9FC (4 bytes)
.data 0x8021D9FC # address
.data 0x00000004 # size
.data 0x4BDEECD4 # 8021D9FC => b -0x0021132C /* 8000C6D0 */
# region @ 80220EBC (4 bytes)
.data 0x80220EBC # address
.data 0x00000004 # size
.data 0x4BDEB824 # 80220EBC => b -0x002147DC /* 8000C6E0 */
# region @ 80229CF0 (4 bytes)
.data 0x80229CF0 # address
.data 0x00000004 # size
.data 0x2C000001 # 80229CF0 => cmpwi r0, 1
# region @ 8022A4F0 (4 bytes)
.data 0x8022A4F0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022A4F0 => li r4, 0xFFFFFF00
# region @ 8022A520 (4 bytes)
.data 0x8022A520 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022A520 => li r4, 0xFFFFFE80
# region @ 8022A550 (4 bytes)
.data 0x8022A550 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022A550 => li r4, 0xFFFFFDB0
# region @ 8022D1EC (4 bytes)
.data 0x8022D1EC # address
.data 0x00000004 # size
.data 0x60000000 # 8022D1EC => nop
# region @ 8022D920 (4 bytes)
.data 0x8022D920 # address
.data 0x00000004 # size
.data 0x41810630 # 8022D920 => bgt +0x00000630 /* 8022DF50 */
# region @ 8022EC44 (4 bytes)
.data 0x8022EC44 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022EC44 => li r4, 0xFFFFFF00
# region @ 8022EC74 (4 bytes)
.data 0x8022EC74 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022EC74 => li r4, 0xFFFFFE80
# region @ 8022ECA4 (4 bytes)
.data 0x8022ECA4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022ECA4 => li r4, 0xFFFFFDB0
# region @ 8022F450 (4 bytes)
.data 0x8022F450 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022F450 => li r4, 0xFFFFFF00
# region @ 8022F480 (4 bytes)
.data 0x8022F480 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022F480 => li r4, 0xFFFFFE80
# region @ 8022F4B0 (4 bytes)
.data 0x8022F4B0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022F4B0 => li r4, 0xFFFFFDB0
# region @ 80230A54 (4 bytes)
.data 0x80230A54 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80230A54 => li r4, 0xFFFFFF00
# region @ 80230A84 (4 bytes)
.data 0x80230A84 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80230A84 => li r4, 0xFFFFFE80
# region @ 80230AB4 (4 bytes)
.data 0x80230AB4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80230AB4 => li r4, 0xFFFFFDB0
# region @ 802317C4 (4 bytes)
.data 0x802317C4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802317C4 => li r4, 0xFFFFFF00
# region @ 802317F4 (4 bytes)
.data 0x802317F4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802317F4 => li r4, 0xFFFFFE80
# region @ 80231824 (4 bytes)
.data 0x80231824 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80231824 => li r4, 0xFFFFFDB0
# region @ 802320B8 (4 bytes)
.data 0x802320B8 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802320B8 => li r4, 0xFFFFFF00
# region @ 802320F0 (4 bytes)
.data 0x802320F0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802320F0 => li r4, 0xFFFFFE80
# region @ 80232128 (4 bytes)
.data 0x80232128 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80232128 => li r4, 0xFFFFFDB0
# region @ 80234164 (4 bytes)
.data 0x80234164 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80234164 => li r4, 0xFFFFFF00
# region @ 80234194 (4 bytes)
.data 0x80234194 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80234194 => li r4, 0xFFFFFE80
# region @ 802341C4 (4 bytes)
.data 0x802341C4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802341C4 => li r4, 0xFFFFFDB0
# region @ 80236790 (4 bytes)
.data 0x80236790 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80236790 => li r4, 0xFFFFFF00
# region @ 802367CC (4 bytes)
.data 0x802367CC # address
.data 0x00000004 # size
.data 0x3880FE80 # 802367CC => li r4, 0xFFFFFE80
# region @ 80236808 (4 bytes)
.data 0x80236808 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80236808 => li r4, 0xFFFFFDB0
# region @ 80236F68 (4 bytes)
.data 0x80236F68 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80236F68 => li r4, 0xFFFFFF00
# region @ 80236F98 (4 bytes)
.data 0x80236F98 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80236F98 => li r4, 0xFFFFFE80
# region @ 80236FC8 (4 bytes)
.data 0x80236FC8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80236FC8 => li r4, 0xFFFFFDB0
# region @ 8023797C (4 bytes)
.data 0x8023797C # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023797C => li r4, 0xFFFFFF00
# region @ 802379AC (4 bytes)
.data 0x802379AC # address
.data 0x00000004 # size
.data 0x3880FE80 # 802379AC => li r4, 0xFFFFFE80
# region @ 802379DC (4 bytes)
.data 0x802379DC # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802379DC => li r4, 0xFFFFFDB0
# region @ 80238354 (4 bytes)
.data 0x80238354 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80238354 => li r4, 0xFFFFFF00
# region @ 80238384 (4 bytes)
.data 0x80238384 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80238384 => li r4, 0xFFFFFE80
# region @ 802383B4 (4 bytes)
.data 0x802383B4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802383B4 => li r4, 0xFFFFFDB0
# region @ 8023BC84 (4 bytes)
.data 0x8023BC84 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023BC84 => li r4, 0xFFFFFF00
# region @ 8023BCB4 (4 bytes)
.data 0x8023BCB4 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023BCB4 => li r4, 0xFFFFFE80
# region @ 8023BCE4 (4 bytes)
.data 0x8023BCE4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023BCE4 => li r4, 0xFFFFFDB0
# region @ 80250CB0 (4 bytes)
.data 0x80250CB0 # address
.data 0x00000004 # size
.data 0x60000000 # 80250CB0 => nop
# region @ 80268A88 (4 bytes)
.data 0x80268A88 # address
.data 0x00000004 # size
.data 0x60000000 # 80268A88 => nop
# region @ 8026E738 (4 bytes)
.data 0x8026E738 # address
.data 0x00000004 # size
.data 0x3884AAFA # 8026E738 => subi r4, r4, 0x5506
# region @ 8026E84C (4 bytes)
.data 0x8026E84C # address
.data 0x00000004 # size
.data 0x3863AAFA # 8026E84C => subi r3, r3, 0x5506
# region @ 8026E8D4 (4 bytes)
.data 0x8026E8D4 # address
.data 0x00000004 # size
.data 0x3883AAFA # 8026E8D4 => subi r4, r3, 0x5506
# region @ 802BC3E0 (4 bytes)
.data 0x802BC3E0 # address
.data 0x00000004 # size
.data 0x4BD515A0 # 802BC3E0 => b -0x002AEA60 /* 8000D980 */
# region @ 802FC968 (4 bytes)
.data 0x802FC968 # address
.data 0x00000004 # size
.data 0x2C030001 # 802FC968 => cmpwi r3, 1
# region @ 803025CC (28 bytes)
.data 0x803025CC # address
.data 0x0000001C # size
.data 0x48000020 # 803025CC => b +0x00000020 /* 803025EC */
.data 0x3863A830 # 803025D0 => subi r3, r3, 0x57D0
.data 0x800DB994 # 803025D4 => lwz r0, [r13 - 0x466C]
.data 0x2C000023 # 803025D8 => cmpwi r0, 35
.data 0x40820008 # 803025DC => bne +0x00000008 /* 803025E4 */
.data 0x3863FB28 # 803025E0 => subi r3, r3, 0x04D8
.data 0x4800008C # 803025E4 => b +0x0000008C /* 80302670 */
# region @ 8030266C (4 bytes)
.data 0x8030266C # address
.data 0x00000004 # size
.data 0x4BFFFF64 # 8030266C => b -0x0000009C /* 803025D0 */
# region @ 803360CC (4 bytes)
.data 0x803360CC # address
.data 0x00000004 # size
.data 0x4BCD78D4 # 803360CC => b -0x0032872C /* 8000D9A0 */
# region @ 80356D64 (4 bytes)
.data 0x80356D64 # address
.data 0x00000004 # size
.data 0x388001E8 # 80356D64 => li r4, 0x01E8
# region @ 80356D88 (4 bytes)
.data 0x80356D88 # address
.data 0x00000004 # size
.data 0x4BCB7459 # 80356D88 => bl -0x00348BA8 /* 8000E1E0 */
# region @ 80356DF8 (4 bytes)
.data 0x80356DF8 # address
.data 0x00000004 # size
.data 0x388001E8 # 80356DF8 => li r4, 0x01E8
# region @ 80356E08 (4 bytes)
.data 0x80356E08 # address
.data 0x00000004 # size
.data 0x4BCB73D9 # 80356E08 => bl -0x00348C28 /* 8000E1E0 */
# region @ 804B6E58 (8 bytes)
.data 0x804B6E58 # address
.data 0x00000008 # size
.data 0x70808080 # 804B6E58 => andi. r0, r4, 0x8080
.data 0x60707070 # 804B6E5C => ori r16, r3, 0x7070
# region @ 804CA61C (4 bytes)
.data 0x804CA61C # address
.data 0x00000004 # size
.data 0x0000001E # 804CA61C => .invalid
# region @ 804CA674 (4 bytes)
.data 0x804CA674 # address
.data 0x00000004 # size
.data 0x00000028 # 804CA674 => .invalid
# region @ 804CA6A0 (4 bytes)
.data 0x804CA6A0 # address
.data 0x00000004 # size
.data 0x00000032 # 804CA6A0 => .invalid
# region @ 804CA6CC (4 bytes)
.data 0x804CA6CC # address
.data 0x00000004 # size
.data 0x0000003C # 804CA6CC => .invalid
# region @ 804CA6DC (4 bytes)
.data 0x804CA6DC # address
.data 0x00000004 # size
.data 0x0018003C # 804CA6DC => .invalid
# region @ 804CA934 (4 bytes)
.data 0x804CA934 # address
.data 0x00000004 # size
.data 0x00000028 # 804CA934 => .invalid
# region @ 804CF290 (4 bytes)
.data 0x804CF290 # address
.data 0x00000004 # size
.data 0xFF0074EE # 804CF290 => fsel f24, f0, f14, f19
# region @ 805D3F6C (4 bytes)
.data 0x805D3F6C # address
.data 0x00000004 # size
.data 0x435C0000 # 805D3F6C => bc 26, 28, +0x00000000 /* 805D3F6C */
# region @ 805D5C08 (4 bytes)
.data 0x805D5C08 # address
.data 0x00000004 # size
.data 0x46AFC800 # 805D5C08 => .invalid sc
# region @ 805D5EA8 (4 bytes)
.data 0x805D5EA8 # address
.data 0x00000004 # size
.data 0x43480000 # 805D5EA8 => bc 26, 8, +0x00000000 /* 805D5EA8 */
# end sentinel
.data 0x00000000 # address
.data 0x00000000 # size
@@ -1,552 +0,0 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
# region @ 8000B088 (88 bytes)
.data 0x8000B088 # address
.data 0x00000058 # size
.data 0x7FA3EB78 # 8000B088 => mr r3, r29
.data 0x38800000 # 8000B08C => li r4, 0x0000
.data 0x481B1C09 # 8000B090 => bl +0x001B1C08 /* 801BCC98 */
.data 0x7FA3EB78 # 8000B094 => mr r3, r29
.data 0x481B1ED8 # 8000B098 => b +0x001B1ED8 /* 801BCF70 */
.data 0x881F0000 # 8000B09C => lbz r0, [r31]
.data 0x28090001 # 8000B0A0 => cmplwi r9, 1
.data 0x4082000C # 8000B0A4 => bne +0x0000000C /* 8000B0B0 */
.data 0x881F0001 # 8000B0A8 => lbz r0, [r31 + 0x0001]
.data 0x3BFF0002 # 8000B0AC => addi r31, r31, 0x0002
.data 0x48100B58 # 8000B0B0 => b +0x00100B58 /* 8010BC08 */
.data 0x39200000 # 8000B0B4 => li r9, 0x0000
.data 0x48100AE9 # 8000B0B8 => bl +0x00100AE8 /* 8010BBA0 */
.data 0x7F43D378 # 8000B0BC => mr r3, r26
.data 0x7F64DB78 # 8000B0C0 => mr r4, r27
.data 0x7F85E378 # 8000B0C4 => mr r5, r28
.data 0x7FA6EB78 # 8000B0C8 => mr r6, r29
.data 0x7FC7F378 # 8000B0CC => mr r7, r30
.data 0x7FE8FB78 # 8000B0D0 => mr r8, r31
.data 0x39200001 # 8000B0D4 => li r9, 0x0001
.data 0x48100AC9 # 8000B0D8 => bl +0x00100AC8 /* 8010BBA0 */
.data 0x4810300C # 8000B0DC => b +0x0010300C /* 8010E0E8 */
# region @ 8000B5C8 (20 bytes)
.data 0x8000B5C8 # address
.data 0x00000014 # size
.data 0x80630098 # 8000B5C8 => lwz r3, [r3 + 0x0098]
.data 0x483D8F71 # 8000B5CC => bl +0x003D8F70 /* 803E453C */
.data 0x807F042C # 8000B5D0 => lwz r3, [r31 + 0x042C]
.data 0x809F0430 # 8000B5D4 => lwz r4, [r31 + 0x0430]
.data 0x48178DEC # 8000B5D8 => b +0x00178DEC /* 801843C4 */
# region @ 8000BBD0 (32 bytes)
.data 0x8000BBD0 # address
.data 0x00000020 # size
.data 0x809F0370 # 8000BBD0 => lwz r4, [r31 + 0x0370]
.data 0x3884FC00 # 8000BBD4 => subi r4, r4, 0x0400
.data 0x909F0370 # 8000BBD8 => stw [r31 + 0x0370], r4
.data 0x807F0014 # 8000BBDC => lwz r3, [r31 + 0x0014]
.data 0x28030000 # 8000BBE0 => cmplwi r3, 0
.data 0x41820008 # 8000BBE4 => beq +0x00000008 /* 8000BBEC */
.data 0x90830060 # 8000BBE8 => stw [r3 + 0x0060], r4
.data 0x48165678 # 8000BBEC => b +0x00165678 /* 80171264 */
# region @ 8000C3F8 (124 bytes)
.data 0x8000C3F8 # address
.data 0x0000007C # size
.data 0x28040000 # 8000C3F8 => cmplwi r4, 0
.data 0x4D820020 # 8000C3FC => beqlr
.data 0x9421FFF0 # 8000C400 => stwu [r1 - 0x0010], r1
.data 0x481B0898 # 8000C404 => b +0x001B0898 /* 801BCC9C */
.data 0x9421FFE0 # 8000C408 => stwu [r1 - 0x0020], r1
.data 0x7C0802A6 # 8000C40C => mflr r0
.data 0x90010024 # 8000C410 => stw [r1 + 0x0024], r0
.data 0xBF410008 # 8000C414 => stmw [r1 + 0x0008], r26
.data 0x7C7F1B78 # 8000C418 => mr r31, r3
.data 0x4BFFFFDD # 8000C41C => bl -0x00000024 /* 8000C3F8 */
.data 0x3BC00000 # 8000C420 => li r30, 0x0000
.data 0x3BBF0D04 # 8000C424 => addi r29, r31, 0x0D04
.data 0x837F032C # 8000C428 => lwz r27, [r31 + 0x032C]
.data 0x839D0000 # 8000C42C => lwz r28, [r29]
.data 0x7F83E379 # 8000C430 => mr. r3, r28
.data 0x41820018 # 8000C434 => beq +0x00000018 /* 8000C44C */
.data 0x38800001 # 8000C438 => li r4, 0x0001
.data 0x480FEDC9 # 8000C43C => bl +0x000FEDC8 /* 8010B204 */
.data 0x7F83E378 # 8000C440 => mr r3, r28
.data 0x38800001 # 8000C444 => li r4, 0x0001
.data 0x480FEF49 # 8000C448 => bl +0x000FEF48 /* 8010B390 */
.data 0x3BBD0004 # 8000C44C => addi r29, r29, 0x0004
.data 0x3BDE0001 # 8000C450 => addi r30, r30, 0x0001
.data 0x2C1E000D # 8000C454 => cmpwi r30, 13
.data 0x4180FFD4 # 8000C458 => blt -0x0000002C /* 8000C42C */
.data 0x937F032C # 8000C45C => stw [r31 + 0x032C], r27
.data 0xBB410008 # 8000C460 => lmw r26, [r1 + 0x0008]
.data 0x80010024 # 8000C464 => lwz r0, [r1 + 0x0024]
.data 0x7C0803A6 # 8000C468 => mtlr r0
.data 0x38210020 # 8000C46C => addi r1, r1, 0x0020
.data 0x4E800020 # 8000C470 => blr
# region @ 8000C640 (20 bytes)
.data 0x8000C640 # address
.data 0x00000014 # size
.data 0x54800673 # 8000C640 => rlwinm. r0, r4, 0, 25, 25
.data 0x41820008 # 8000C644 => beq +0x00000008 /* 8000C64C */
.data 0x38800000 # 8000C648 => li r4, 0x0000
.data 0x38040009 # 8000C64C => addi r0, r4, 0x0009
.data 0x4810C98C # 8000C650 => b +0x0010C98C /* 80118FDC */
# region @ 8000C6D0 (32 bytes)
.data 0x8000C6D0 # address
.data 0x00000020 # size
.data 0x38000001 # 8000C6D0 => li r0, 0x0001
.data 0x901D0054 # 8000C6D4 => stw [r29 + 0x0054], r0
.data 0x807D0024 # 8000C6D8 => lwz r3, [r29 + 0x0024]
.data 0x48212210 # 8000C6DC => b +0x00212210 /* 8021E8EC */
.data 0x38000001 # 8000C6E0 => li r0, 0x0001
.data 0x901F0378 # 8000C6E4 => stw [r31 + 0x0378], r0
.data 0x807F0024 # 8000C6E8 => lwz r3, [r31 + 0x0024]
.data 0x482156C0 # 8000C6EC => b +0x002156C0 /* 80221DAC */
# region @ 8000C8A0 (20 bytes)
.data 0x8000C8A0 # address
.data 0x00000014 # size
.data 0x1C00000A # 8000C8A0 => mulli r0, r0, 10
.data 0x57E407BD # 8000C8A4 => rlwinm. r4, r31, 0, 30, 30
.data 0x41820008 # 8000C8A8 => beq +0x00000008 /* 8000C8B0 */
.data 0x7FA00734 # 8000C8AC => extsh r0, r29
.data 0x48106190 # 8000C8B0 => b +0x00106190 /* 80112A40 */
# region @ 8000C8C0 (16 bytes)
.data 0x8000C8C0 # address
.data 0x00000010 # size
.data 0x7000000F # 8000C8C0 => andi. r0, r0, 0x000F
.data 0x7000004F # 8000C8C4 => andi. r0, r0, 0x004F
.data 0x2C000004 # 8000C8C8 => cmpwi r0, 4
.data 0x4E800020 # 8000C8CC => blr
# region @ 8000D980 (20 bytes)
.data 0x8000D980 # address
.data 0x00000014 # size
.data 0x807C0000 # 8000D980 => lwz r3, [r28]
.data 0x2C030013 # 8000D984 => cmpwi r3, 19
.data 0x40820008 # 8000D988 => bne +0x00000008 /* 8000D990 */
.data 0x38600002 # 8000D98C => li r3, 0x0002
.data 0x482AFB9C # 8000D990 => b +0x002AFB9C /* 802BD52C */
# region @ 8000D9A0 (24 bytes)
.data 0x8000D9A0 # address
.data 0x00000018 # size
.data 0xC042FC80 # 8000D9A0 => lfs f2, [r2 - 0x0380]
.data 0x807E0030 # 8000D9A4 => lwz r3, [r30 + 0x0030]
.data 0x70630020 # 8000D9A8 => andi. r3, r3, 0x0020
.data 0x41820008 # 8000D9AC => beq +0x00000008 /* 8000D9B4 */
.data 0xC042FC98 # 8000D9B0 => lfs f2, [r2 - 0x0368]
.data 0x48329C38 # 8000D9B4 => b +0x00329C38 /* 803375EC */
# region @ 8000E1E0 (28 bytes)
.data 0x8000E1E0 # address
.data 0x0000001C # size
.data 0x7FC802A6 # 8000E1E0 => mflr r30
.data 0x38A00000 # 8000E1E4 => li r5, 0x0000
.data 0x38C0001E # 8000E1E8 => li r6, 0x001E
.data 0x38E00040 # 8000E1EC => li r7, 0x0040
.data 0x48078715 # 8000E1F0 => bl +0x00078714 /* 80086904 */
.data 0x7FC803A6 # 8000E1F4 => mtlr r30
.data 0x4E800020 # 8000E1F8 => blr
# region @ 80013364 (4 bytes)
.data 0x80013364 # address
.data 0x00000004 # size
.data 0x4BFFFCC0 # 80013364 => b -0x00000340 /* 80013024 */
# region @ 800146A4 (4 bytes)
.data 0x800146A4 # address
.data 0x00000004 # size
.data 0x4BFF821D # 800146A4 => bl -0x00007DE4 /* 8000C8C0 */
# region @ 80016174 (4 bytes)
.data 0x80016174 # address
.data 0x00000004 # size
.data 0x4BFF6751 # 80016174 => bl -0x000098B0 /* 8000C8C4 */
# region @ 8009198C (8 bytes)
.data 0x8009198C # address
.data 0x00000008 # size
.data 0x4800024D # 8009198C => bl +0x0000024C /* 80091BD8 */
.data 0xB3C3032C # 80091990 => sth [r3 + 0x032C], r30
# region @ 800BCBD0 (4 bytes)
.data 0x800BCBD0 # address
.data 0x00000004 # size
.data 0x48000010 # 800BCBD0 => b +0x00000010 /* 800BCBE0 */
# region @ 80104DE0 (4 bytes)
.data 0x80104DE0 # address
.data 0x00000004 # size
.data 0x4182000C # 80104DE0 => beq +0x0000000C /* 80104DEC */
# region @ 80107708 (4 bytes)
.data 0x80107708 # address
.data 0x00000004 # size
.data 0x4800000C # 80107708 => b +0x0000000C /* 80107714 */
# region @ 8010771C (4 bytes)
.data 0x8010771C # address
.data 0x00000004 # size
.data 0x7C030378 # 8010771C => mr r3, r0
# region @ 8010BC04 (4 bytes)
.data 0x8010BC04 # address
.data 0x00000004 # size
.data 0x4BEFF498 # 8010BC04 => b -0x00100B68 /* 8000B09C */
# region @ 8010E0E4 (4 bytes)
.data 0x8010E0E4 # address
.data 0x00000004 # size
.data 0x4BEFCFD0 # 8010E0E4 => b -0x00103030 /* 8000B0B4 */
# region @ 80112A3C (4 bytes)
.data 0x80112A3C # address
.data 0x00000004 # size
.data 0x4BEF9E64 # 80112A3C => b -0x0010619C /* 8000C8A0 */
# region @ 80114634 (4 bytes)
.data 0x80114634 # address
.data 0x00000004 # size
.data 0x38000012 # 80114634 => li r0, 0x0012
# region @ 8011885C (4 bytes)
.data 0x8011885C # address
.data 0x00000004 # size
.data 0x88040016 # 8011885C => lbz r0, [r4 + 0x0016]
# region @ 80118868 (4 bytes)
.data 0x80118868 # address
.data 0x00000004 # size
.data 0x88040017 # 80118868 => lbz r0, [r4 + 0x0017]
# region @ 80118FD8 (4 bytes)
.data 0x80118FD8 # address
.data 0x00000004 # size
.data 0x4BEF3668 # 80118FD8 => b -0x0010C998 /* 8000C640 */
# region @ 8011CD0C (12 bytes)
.data 0x8011CD0C # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CD0C => mr r3, r0
.data 0x3863FFFF # 8011CD10 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CD14 => b -0x00000018 /* 8011CCFC */
# region @ 8011CDC8 (12 bytes)
.data 0x8011CDC8 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CDC8 => mr r3, r0
.data 0x3863FFFF # 8011CDCC => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CDD0 => b -0x00000018 /* 8011CDB8 */
# region @ 8011CE18 (12 bytes)
.data 0x8011CE18 # address
.data 0x0000000C # size
.data 0x7C040378 # 8011CE18 => mr r4, r0
.data 0x3884FFFF # 8011CE1C => subi r4, r4, 0x0001
.data 0x4BFFFFE8 # 8011CE20 => b -0x00000018 /* 8011CE08 */
# region @ 80166848 (8 bytes)
.data 0x80166848 # address
.data 0x00000008 # size
.data 0x3C604005 # 80166848 => lis r3, 0x4005
.data 0x4800009C # 8016684C => b +0x0000009C /* 801668E8 */
# region @ 801668E4 (4 bytes)
.data 0x801668E4 # address
.data 0x00000004 # size
.data 0x4800001C # 801668E4 => b +0x0000001C /* 80166900 */
# region @ 80171260 (4 bytes)
.data 0x80171260 # address
.data 0x00000004 # size
.data 0x4BE9A970 # 80171260 => b -0x00165690 /* 8000BBD0 */
# region @ 80171280 (4 bytes)
.data 0x80171280 # address
.data 0x00000004 # size
.data 0x60800420 # 80171280 => ori r0, r4, 0x0420
# region @ 801843C0 (4 bytes)
.data 0x801843C0 # address
.data 0x00000004 # size
.data 0x4BE87208 # 801843C0 => b -0x00178DF8 /* 8000B5C8 */
# region @ 80184400 (4 bytes)
.data 0x80184400 # address
.data 0x00000004 # size
.data 0x60000000 # 80184400 => nop
# region @ 80189F90 (4 bytes)
.data 0x80189F90 # address
.data 0x00000004 # size
.data 0x60000000 # 80189F90 => nop
# region @ 80193914 (4 bytes)
.data 0x80193914 # address
.data 0x00000004 # size
.data 0x60000000 # 80193914 => nop
# region @ 801BCC98 (4 bytes)
.data 0x801BCC98 # address
.data 0x00000004 # size
.data 0x4BE4F770 # 801BCC98 => b -0x001B0890 /* 8000C408 */
# region @ 801BCF6C (4 bytes)
.data 0x801BCF6C # address
.data 0x00000004 # size
.data 0x4BE4E11C # 801BCF6C => b -0x001B1EE4 /* 8000B088 */
# region @ 801C6604 (4 bytes)
.data 0x801C6604 # address
.data 0x00000004 # size
.data 0x389F02FC # 801C6604 => addi r4, r31, 0x02FC
# region @ 801CB5EC (4 bytes)
.data 0x801CB5EC # address
.data 0x00000004 # size
.data 0x48000010 # 801CB5EC => b +0x00000010 /* 801CB5FC */
# region @ 8021E8E8 (4 bytes)
.data 0x8021E8E8 # address
.data 0x00000004 # size
.data 0x4BDEDDE8 # 8021E8E8 => b -0x00212218 /* 8000C6D0 */
# region @ 80221DA8 (4 bytes)
.data 0x80221DA8 # address
.data 0x00000004 # size
.data 0x4BDEA938 # 80221DA8 => b -0x002156C8 /* 8000C6E0 */
# region @ 8022ABDC (4 bytes)
.data 0x8022ABDC # address
.data 0x00000004 # size
.data 0x2C000001 # 8022ABDC => cmpwi r0, 1
# region @ 8022B3E0 (4 bytes)
.data 0x8022B3E0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022B3E0 => li r4, 0xFFFFFF00
# region @ 8022B410 (4 bytes)
.data 0x8022B410 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022B410 => li r4, 0xFFFFFE80
# region @ 8022B440 (4 bytes)
.data 0x8022B440 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022B440 => li r4, 0xFFFFFDB0
# region @ 8022E128 (4 bytes)
.data 0x8022E128 # address
.data 0x00000004 # size
.data 0x60000000 # 8022E128 => nop
# region @ 8022E85C (4 bytes)
.data 0x8022E85C # address
.data 0x00000004 # size
.data 0x41810630 # 8022E85C => bgt +0x00000630 /* 8022EE8C */
# region @ 8022FB30 (4 bytes)
.data 0x8022FB30 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022FB30 => li r4, 0xFFFFFF00
# region @ 8022FB60 (4 bytes)
.data 0x8022FB60 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022FB60 => li r4, 0xFFFFFE80
# region @ 8022FB90 (4 bytes)
.data 0x8022FB90 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022FB90 => li r4, 0xFFFFFDB0
# region @ 80230340 (4 bytes)
.data 0x80230340 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80230340 => li r4, 0xFFFFFF00
# region @ 80230370 (4 bytes)
.data 0x80230370 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80230370 => li r4, 0xFFFFFE80
# region @ 802303A0 (4 bytes)
.data 0x802303A0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802303A0 => li r4, 0xFFFFFDB0
# region @ 80231940 (4 bytes)
.data 0x80231940 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80231940 => li r4, 0xFFFFFF00
# region @ 80231970 (4 bytes)
.data 0x80231970 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80231970 => li r4, 0xFFFFFE80
# region @ 802319A0 (4 bytes)
.data 0x802319A0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802319A0 => li r4, 0xFFFFFDB0
# region @ 802326B0 (4 bytes)
.data 0x802326B0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802326B0 => li r4, 0xFFFFFF00
# region @ 802326E0 (4 bytes)
.data 0x802326E0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802326E0 => li r4, 0xFFFFFE80
# region @ 80232710 (4 bytes)
.data 0x80232710 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80232710 => li r4, 0xFFFFFDB0
# region @ 80232FA4 (4 bytes)
.data 0x80232FA4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80232FA4 => li r4, 0xFFFFFF00
# region @ 80232FDC (4 bytes)
.data 0x80232FDC # address
.data 0x00000004 # size
.data 0x3880FE80 # 80232FDC => li r4, 0xFFFFFE80
# region @ 80233014 (4 bytes)
.data 0x80233014 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80233014 => li r4, 0xFFFFFDB0
# region @ 80235050 (4 bytes)
.data 0x80235050 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80235050 => li r4, 0xFFFFFF00
# region @ 80235080 (4 bytes)
.data 0x80235080 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80235080 => li r4, 0xFFFFFE80
# region @ 802350B0 (4 bytes)
.data 0x802350B0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802350B0 => li r4, 0xFFFFFDB0
# region @ 8023767C (4 bytes)
.data 0x8023767C # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023767C => li r4, 0xFFFFFF00
# region @ 802376B8 (4 bytes)
.data 0x802376B8 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802376B8 => li r4, 0xFFFFFE80
# region @ 802376F4 (4 bytes)
.data 0x802376F4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802376F4 => li r4, 0xFFFFFDB0
# region @ 80237E54 (4 bytes)
.data 0x80237E54 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80237E54 => li r4, 0xFFFFFF00
# region @ 80237E84 (4 bytes)
.data 0x80237E84 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80237E84 => li r4, 0xFFFFFE80
# region @ 80237EB4 (4 bytes)
.data 0x80237EB4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80237EB4 => li r4, 0xFFFFFDB0
# region @ 80238868 (4 bytes)
.data 0x80238868 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80238868 => li r4, 0xFFFFFF00
# region @ 80238898 (4 bytes)
.data 0x80238898 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80238898 => li r4, 0xFFFFFE80
# region @ 802388C8 (4 bytes)
.data 0x802388C8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802388C8 => li r4, 0xFFFFFDB0
# region @ 80239240 (4 bytes)
.data 0x80239240 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80239240 => li r4, 0xFFFFFF00
# region @ 80239270 (4 bytes)
.data 0x80239270 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80239270 => li r4, 0xFFFFFE80
# region @ 802392A0 (4 bytes)
.data 0x802392A0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802392A0 => li r4, 0xFFFFFDB0
# region @ 8023CB70 (4 bytes)
.data 0x8023CB70 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023CB70 => li r4, 0xFFFFFF00
# region @ 8023CBA0 (4 bytes)
.data 0x8023CBA0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023CBA0 => li r4, 0xFFFFFE80
# region @ 8023CBD0 (4 bytes)
.data 0x8023CBD0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023CBD0 => li r4, 0xFFFFFDB0
# region @ 80251CA4 (4 bytes)
.data 0x80251CA4 # address
.data 0x00000004 # size
.data 0x60000000 # 80251CA4 => nop
# region @ 80269AE4 (4 bytes)
.data 0x80269AE4 # address
.data 0x00000004 # size
.data 0x60000000 # 80269AE4 => nop
# region @ 8026F794 (4 bytes)
.data 0x8026F794 # address
.data 0x00000004 # size
.data 0x3884AAFA # 8026F794 => subi r4, r4, 0x5506
# region @ 8026F8A8 (4 bytes)
.data 0x8026F8A8 # address
.data 0x00000004 # size
.data 0x3863AAFA # 8026F8A8 => subi r3, r3, 0x5506
# region @ 8026F930 (4 bytes)
.data 0x8026F930 # address
.data 0x00000004 # size
.data 0x3883AAFA # 8026F930 => subi r4, r3, 0x5506
# region @ 802BD528 (4 bytes)
.data 0x802BD528 # address
.data 0x00000004 # size
.data 0x4BD50458 # 802BD528 => b -0x002AFBA8 /* 8000D980 */
# region @ 802FDE60 (4 bytes)
.data 0x802FDE60 # address
.data 0x00000004 # size
.data 0x2C030001 # 802FDE60 => cmpwi r3, 1
# region @ 80303A1C (28 bytes)
.data 0x80303A1C # address
.data 0x0000001C # size
.data 0x48000020 # 80303A1C => b +0x00000020 /* 80303A3C */
.data 0x3863A830 # 80303A20 => subi r3, r3, 0x57D0
.data 0x800DB9B4 # 80303A24 => lwz r0, [r13 - 0x464C]
.data 0x2C000023 # 80303A28 => cmpwi r0, 35
.data 0x40820008 # 80303A2C => bne +0x00000008 /* 80303A34 */
.data 0x3863FB28 # 80303A30 => subi r3, r3, 0x04D8
.data 0x4800008C # 80303A34 => b +0x0000008C /* 80303AC0 */
# region @ 80303ABC (4 bytes)
.data 0x80303ABC # address
.data 0x00000004 # size
.data 0x4BFFFF64 # 80303ABC => b -0x0000009C /* 80303A20 */
# region @ 803375E8 (4 bytes)
.data 0x803375E8 # address
.data 0x00000004 # size
.data 0x4BCD63B8 # 803375E8 => b -0x00329C48 /* 8000D9A0 */
# region @ 803582C0 (4 bytes)
.data 0x803582C0 # address
.data 0x00000004 # size
.data 0x388001E8 # 803582C0 => li r4, 0x01E8
# region @ 803582E4 (4 bytes)
.data 0x803582E4 # address
.data 0x00000004 # size
.data 0x4BCB5EFD # 803582E4 => bl -0x0034A104 /* 8000E1E0 */
# region @ 80358354 (4 bytes)
.data 0x80358354 # address
.data 0x00000004 # size
.data 0x388001E8 # 80358354 => li r4, 0x01E8
# region @ 80358364 (4 bytes)
.data 0x80358364 # address
.data 0x00000004 # size
.data 0x4BCB5E7D # 80358364 => bl -0x0034A184 /* 8000E1E0 */
# region @ 804B92F8 (8 bytes)
.data 0x804B92F8 # address
.data 0x00000008 # size
.data 0x70808080 # 804B92F8 => andi. r0, r4, 0x8080
.data 0x60707070 # 804B92FC => ori r16, r3, 0x7070
# region @ 804CCB6C (4 bytes)
.data 0x804CCB6C # address
.data 0x00000004 # size
.data 0x0000001E # 804CCB6C => .invalid
# region @ 804CCBC4 (4 bytes)
.data 0x804CCBC4 # address
.data 0x00000004 # size
.data 0x00000028 # 804CCBC4 => .invalid
# region @ 804CCBF0 (4 bytes)
.data 0x804CCBF0 # address
.data 0x00000004 # size
.data 0x00000032 # 804CCBF0 => .invalid
# region @ 804CCC1C (4 bytes)
.data 0x804CCC1C # address
.data 0x00000004 # size
.data 0x0000003C # 804CCC1C => .invalid
# region @ 804CCC2C (4 bytes)
.data 0x804CCC2C # address
.data 0x00000004 # size
.data 0x0018003C # 804CCC2C => .invalid
# region @ 804CCE84 (4 bytes)
.data 0x804CCE84 # address
.data 0x00000004 # size
.data 0x00000028 # 804CCE84 => .invalid
# region @ 804D17E0 (4 bytes)
.data 0x804D17E0 # address
.data 0x00000004 # size
.data 0xFF0074EE # 804D17E0 => fsel f24, f0, f14, f19
# region @ 805DB40C (4 bytes)
.data 0x805DB40C # address
.data 0x00000004 # size
.data 0x435C0000 # 805DB40C => bc 26, 28, +0x00000000 /* 805DB40C */
# region @ 805DD0A8 (4 bytes)
.data 0x805DD0A8 # address
.data 0x00000004 # size
.data 0x46AFC800 # 805DD0A8 => .invalid sc
# region @ 805DD348 (4 bytes)
.data 0x805DD348 # address
.data 0x00000004 # size
.data 0x43480000 # 805DD348 => bc 26, 8, +0x00000000 /* 805DD348 */
# end sentinel
.data 0x00000000 # address
.data 0x00000000 # size
@@ -1,552 +0,0 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
# region @ 8000B088 (88 bytes)
.data 0x8000B088 # address
.data 0x00000058 # size
.data 0x7FA3EB78 # 8000B088 => mr r3, r29
.data 0x38800000 # 8000B08C => li r4, 0x0000
.data 0x481AEC5D # 8000B090 => bl +0x001AEC5C /* 801B9CEC */
.data 0x7FA3EB78 # 8000B094 => mr r3, r29
.data 0x481AEF2C # 8000B098 => b +0x001AEF2C /* 801B9FC4 */
.data 0x881F0000 # 8000B09C => lbz r0, [r31]
.data 0x28090001 # 8000B0A0 => cmplwi r9, 1
.data 0x4082000C # 8000B0A4 => bne +0x0000000C /* 8000B0B0 */
.data 0x881F0001 # 8000B0A8 => lbz r0, [r31 + 0x0001]
.data 0x3BFF0002 # 8000B0AC => addi r31, r31, 0x0002
.data 0x48100A44 # 8000B0B0 => b +0x00100A44 /* 8010BAF4 */
.data 0x39200000 # 8000B0B4 => li r9, 0x0000
.data 0x481009D5 # 8000B0B8 => bl +0x001009D4 /* 8010BA8C */
.data 0x7F43D378 # 8000B0BC => mr r3, r26
.data 0x7F64DB78 # 8000B0C0 => mr r4, r27
.data 0x7F85E378 # 8000B0C4 => mr r5, r28
.data 0x7FA6EB78 # 8000B0C8 => mr r6, r29
.data 0x7FC7F378 # 8000B0CC => mr r7, r30
.data 0x7FE8FB78 # 8000B0D0 => mr r8, r31
.data 0x39200001 # 8000B0D4 => li r9, 0x0001
.data 0x481009B5 # 8000B0D8 => bl +0x001009B4 /* 8010BA8C */
.data 0x48102E4C # 8000B0DC => b +0x00102E4C /* 8010DF28 */
# region @ 8000B5C8 (20 bytes)
.data 0x8000B5C8 # address
.data 0x00000014 # size
.data 0x80630098 # 8000B5C8 => lwz r3, [r3 + 0x0098]
.data 0x483D8D21 # 8000B5CC => bl +0x003D8D20 /* 803E42EC */
.data 0x807F042C # 8000B5D0 => lwz r3, [r31 + 0x042C]
.data 0x809F0430 # 8000B5D4 => lwz r4, [r31 + 0x0430]
.data 0x48178D4C # 8000B5D8 => b +0x00178D4C /* 80184324 */
# region @ 8000BBD0 (32 bytes)
.data 0x8000BBD0 # address
.data 0x00000020 # size
.data 0x809F0370 # 8000BBD0 => lwz r4, [r31 + 0x0370]
.data 0x3884FC00 # 8000BBD4 => subi r4, r4, 0x0400
.data 0x909F0370 # 8000BBD8 => stw [r31 + 0x0370], r4
.data 0x807F0014 # 8000BBDC => lwz r3, [r31 + 0x0014]
.data 0x28030000 # 8000BBE0 => cmplwi r3, 0
.data 0x41820008 # 8000BBE4 => beq +0x00000008 /* 8000BBEC */
.data 0x90830060 # 8000BBE8 => stw [r3 + 0x0060], r4
.data 0x481654E4 # 8000BBEC => b +0x001654E4 /* 801710D0 */
# region @ 8000C3F8 (124 bytes)
.data 0x8000C3F8 # address
.data 0x0000007C # size
.data 0x28040000 # 8000C3F8 => cmplwi r4, 0
.data 0x4D820020 # 8000C3FC => beqlr
.data 0x9421FFF0 # 8000C400 => stwu [r1 - 0x0010], r1
.data 0x481AD8EC # 8000C404 => b +0x001AD8EC /* 801B9CF0 */
.data 0x9421FFE0 # 8000C408 => stwu [r1 - 0x0020], r1
.data 0x7C0802A6 # 8000C40C => mflr r0
.data 0x90010024 # 8000C410 => stw [r1 + 0x0024], r0
.data 0xBF410008 # 8000C414 => stmw [r1 + 0x0008], r26
.data 0x7C7F1B78 # 8000C418 => mr r31, r3
.data 0x4BFFFFDD # 8000C41C => bl -0x00000024 /* 8000C3F8 */
.data 0x3BC00000 # 8000C420 => li r30, 0x0000
.data 0x3BBF0D04 # 8000C424 => addi r29, r31, 0x0D04
.data 0x837F032C # 8000C428 => lwz r27, [r31 + 0x032C]
.data 0x839D0000 # 8000C42C => lwz r28, [r29]
.data 0x7F83E379 # 8000C430 => mr. r3, r28
.data 0x41820018 # 8000C434 => beq +0x00000018 /* 8000C44C */
.data 0x38800001 # 8000C438 => li r4, 0x0001
.data 0x480FEC5D # 8000C43C => bl +0x000FEC5C /* 8010B098 */
.data 0x7F83E378 # 8000C440 => mr r3, r28
.data 0x38800001 # 8000C444 => li r4, 0x0001
.data 0x480FEDCD # 8000C448 => bl +0x000FEDCC /* 8010B214 */
.data 0x3BBD0004 # 8000C44C => addi r29, r29, 0x0004
.data 0x3BDE0001 # 8000C450 => addi r30, r30, 0x0001
.data 0x2C1E000D # 8000C454 => cmpwi r30, 13
.data 0x4180FFD4 # 8000C458 => blt -0x0000002C /* 8000C42C */
.data 0x937F032C # 8000C45C => stw [r31 + 0x032C], r27
.data 0xBB410008 # 8000C460 => lmw r26, [r1 + 0x0008]
.data 0x80010024 # 8000C464 => lwz r0, [r1 + 0x0024]
.data 0x7C0803A6 # 8000C468 => mtlr r0
.data 0x38210020 # 8000C46C => addi r1, r1, 0x0020
.data 0x4E800020 # 8000C470 => blr
# region @ 8000C640 (20 bytes)
.data 0x8000C640 # address
.data 0x00000014 # size
.data 0x54800673 # 8000C640 => rlwinm. r0, r4, 0, 25, 25
.data 0x41820008 # 8000C644 => beq +0x00000008 /* 8000C64C */
.data 0x38800000 # 8000C648 => li r4, 0x0000
.data 0x38040009 # 8000C64C => addi r0, r4, 0x0009
.data 0x4810C848 # 8000C650 => b +0x0010C848 /* 80118E98 */
# region @ 8000C6D0 (32 bytes)
.data 0x8000C6D0 # address
.data 0x00000020 # size
.data 0x38000001 # 8000C6D0 => li r0, 0x0001
.data 0x901D0054 # 8000C6D4 => stw [r29 + 0x0054], r0
.data 0x807D0024 # 8000C6D8 => lwz r3, [r29 + 0x0024]
.data 0x48211FC4 # 8000C6DC => b +0x00211FC4 /* 8021E6A0 */
.data 0x38000001 # 8000C6E0 => li r0, 0x0001
.data 0x901F0378 # 8000C6E4 => stw [r31 + 0x0378], r0
.data 0x807F0024 # 8000C6E8 => lwz r3, [r31 + 0x0024]
.data 0x48215474 # 8000C6EC => b +0x00215474 /* 80221B60 */
# region @ 8000C8A0 (20 bytes)
.data 0x8000C8A0 # address
.data 0x00000014 # size
.data 0x1C00000A # 8000C8A0 => mulli r0, r0, 10
.data 0x57E407BD # 8000C8A4 => rlwinm. r4, r31, 0, 30, 30
.data 0x41820008 # 8000C8A8 => beq +0x00000008 /* 8000C8B0 */
.data 0x7FA00734 # 8000C8AC => extsh r0, r29
.data 0x48105F44 # 8000C8B0 => b +0x00105F44 /* 801127F4 */
# region @ 8000C8C0 (16 bytes)
.data 0x8000C8C0 # address
.data 0x00000010 # size
.data 0x7000000F # 8000C8C0 => andi. r0, r0, 0x000F
.data 0x7000004F # 8000C8C4 => andi. r0, r0, 0x004F
.data 0x2C000004 # 8000C8C8 => cmpwi r0, 4
.data 0x4E800020 # 8000C8CC => blr
# region @ 8000D980 (20 bytes)
.data 0x8000D980 # address
.data 0x00000014 # size
.data 0x807C0000 # 8000D980 => lwz r3, [r28]
.data 0x2C030013 # 8000D984 => cmpwi r3, 19
.data 0x40820008 # 8000D988 => bne +0x00000008 /* 8000D990 */
.data 0x38600002 # 8000D98C => li r3, 0x0002
.data 0x482AF934 # 8000D990 => b +0x002AF934 /* 802BD2C4 */
# region @ 8000D9A0 (24 bytes)
.data 0x8000D9A0 # address
.data 0x00000018 # size
.data 0xC042FC80 # 8000D9A0 => lfs f2, [r2 - 0x0380]
.data 0x807E0030 # 8000D9A4 => lwz r3, [r30 + 0x0030]
.data 0x70630020 # 8000D9A8 => andi. r3, r3, 0x0020
.data 0x41820008 # 8000D9AC => beq +0x00000008 /* 8000D9B4 */
.data 0xC042FC98 # 8000D9B0 => lfs f2, [r2 - 0x0368]
.data 0x483299EC # 8000D9B4 => b +0x003299EC /* 803373A0 */
# region @ 8000E1E0 (28 bytes)
.data 0x8000E1E0 # address
.data 0x0000001C # size
.data 0x7FC802A6 # 8000E1E0 => mflr r30
.data 0x38A00000 # 8000E1E4 => li r5, 0x0000
.data 0x38C0001E # 8000E1E8 => li r6, 0x001E
.data 0x38E00040 # 8000E1EC => li r7, 0x0040
.data 0x480786C5 # 8000E1F0 => bl +0x000786C4 /* 800868B4 */
.data 0x7FC803A6 # 8000E1F4 => mtlr r30
.data 0x4E800020 # 8000E1F8 => blr
# region @ 8001304C (4 bytes)
.data 0x8001304C # address
.data 0x00000004 # size
.data 0x4BFFFCC0 # 8001304C => b -0x00000340 /* 80012D0C */
# region @ 800142BC (4 bytes)
.data 0x800142BC # address
.data 0x00000004 # size
.data 0x4BFF8605 # 800142BC => bl -0x000079FC /* 8000C8C0 */
# region @ 80015CE4 (4 bytes)
.data 0x80015CE4 # address
.data 0x00000004 # size
.data 0x4BFF6BE1 # 80015CE4 => bl -0x00009420 /* 8000C8C4 */
# region @ 8009193C (8 bytes)
.data 0x8009193C # address
.data 0x00000008 # size
.data 0x4800024D # 8009193C => bl +0x0000024C /* 80091B88 */
.data 0xB3C3032C # 80091940 => sth [r3 + 0x032C], r30
# region @ 800BCB80 (4 bytes)
.data 0x800BCB80 # address
.data 0x00000004 # size
.data 0x48000010 # 800BCB80 => b +0x00000010 /* 800BCB90 */
# region @ 80104CA4 (4 bytes)
.data 0x80104CA4 # address
.data 0x00000004 # size
.data 0x4182000C # 80104CA4 => beq +0x0000000C /* 80104CB0 */
# region @ 801075D4 (4 bytes)
.data 0x801075D4 # address
.data 0x00000004 # size
.data 0x4800000C # 801075D4 => b +0x0000000C /* 801075E0 */
# region @ 801075E8 (4 bytes)
.data 0x801075E8 # address
.data 0x00000004 # size
.data 0x7C030378 # 801075E8 => mr r3, r0
# region @ 8010BAF0 (4 bytes)
.data 0x8010BAF0 # address
.data 0x00000004 # size
.data 0x4BEFF5AC # 8010BAF0 => b -0x00100A54 /* 8000B09C */
# region @ 8010DF24 (4 bytes)
.data 0x8010DF24 # address
.data 0x00000004 # size
.data 0x4BEFD190 # 8010DF24 => b -0x00102E70 /* 8000B0B4 */
# region @ 801127F0 (4 bytes)
.data 0x801127F0 # address
.data 0x00000004 # size
.data 0x4BEFA0B0 # 801127F0 => b -0x00105F50 /* 8000C8A0 */
# region @ 80114524 (4 bytes)
.data 0x80114524 # address
.data 0x00000004 # size
.data 0x38000012 # 80114524 => li r0, 0x0012
# region @ 80118764 (4 bytes)
.data 0x80118764 # address
.data 0x00000004 # size
.data 0x88040016 # 80118764 => lbz r0, [r4 + 0x0016]
# region @ 80118770 (4 bytes)
.data 0x80118770 # address
.data 0x00000004 # size
.data 0x88040017 # 80118770 => lbz r0, [r4 + 0x0017]
# region @ 80118E94 (4 bytes)
.data 0x80118E94 # address
.data 0x00000004 # size
.data 0x4BEF37AC # 80118E94 => b -0x0010C854 /* 8000C640 */
# region @ 8011CC6C (12 bytes)
.data 0x8011CC6C # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CC6C => mr r3, r0
.data 0x3863FFFF # 8011CC70 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CC74 => b -0x00000018 /* 8011CC5C */
# region @ 8011CD28 (12 bytes)
.data 0x8011CD28 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CD28 => mr r3, r0
.data 0x3863FFFF # 8011CD2C => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CD30 => b -0x00000018 /* 8011CD18 */
# region @ 8011CD78 (12 bytes)
.data 0x8011CD78 # address
.data 0x0000000C # size
.data 0x7C040378 # 8011CD78 => mr r4, r0
.data 0x3884FFFF # 8011CD7C => subi r4, r4, 0x0001
.data 0x4BFFFFE8 # 8011CD80 => b -0x00000018 /* 8011CD68 */
# region @ 8016679C (8 bytes)
.data 0x8016679C # address
.data 0x00000008 # size
.data 0x3C604005 # 8016679C => lis r3, 0x4005
.data 0x4800009C # 801667A0 => b +0x0000009C /* 8016683C */
# region @ 80166838 (4 bytes)
.data 0x80166838 # address
.data 0x00000004 # size
.data 0x4800001C # 80166838 => b +0x0000001C /* 80166854 */
# region @ 801710CC (4 bytes)
.data 0x801710CC # address
.data 0x00000004 # size
.data 0x4BE9AB04 # 801710CC => b -0x001654FC /* 8000BBD0 */
# region @ 801710EC (4 bytes)
.data 0x801710EC # address
.data 0x00000004 # size
.data 0x60800420 # 801710EC => ori r0, r4, 0x0420
# region @ 80184320 (4 bytes)
.data 0x80184320 # address
.data 0x00000004 # size
.data 0x4BE872A8 # 80184320 => b -0x00178D58 /* 8000B5C8 */
# region @ 80184360 (4 bytes)
.data 0x80184360 # address
.data 0x00000004 # size
.data 0x60000000 # 80184360 => nop
# region @ 80189EF0 (4 bytes)
.data 0x80189EF0 # address
.data 0x00000004 # size
.data 0x60000000 # 80189EF0 => nop
# region @ 80193874 (4 bytes)
.data 0x80193874 # address
.data 0x00000004 # size
.data 0x60000000 # 80193874 => nop
# region @ 801B9CEC (4 bytes)
.data 0x801B9CEC # address
.data 0x00000004 # size
.data 0x4BE5271C # 801B9CEC => b -0x001AD8E4 /* 8000C408 */
# region @ 801B9FC0 (4 bytes)
.data 0x801B9FC0 # address
.data 0x00000004 # size
.data 0x4BE510C8 # 801B9FC0 => b -0x001AEF38 /* 8000B088 */
# region @ 801C642C (4 bytes)
.data 0x801C642C # address
.data 0x00000004 # size
.data 0x389F02FC # 801C642C => addi r4, r31, 0x02FC
# region @ 801CA7AC (4 bytes)
.data 0x801CA7AC # address
.data 0x00000004 # size
.data 0x48000010 # 801CA7AC => b +0x00000010 /* 801CA7BC */
# region @ 8021E69C (4 bytes)
.data 0x8021E69C # address
.data 0x00000004 # size
.data 0x4BDEE034 # 8021E69C => b -0x00211FCC /* 8000C6D0 */
# region @ 80221B5C (4 bytes)
.data 0x80221B5C # address
.data 0x00000004 # size
.data 0x4BDEAB84 # 80221B5C => b -0x0021547C /* 8000C6E0 */
# region @ 8022A990 (4 bytes)
.data 0x8022A990 # address
.data 0x00000004 # size
.data 0x2C000001 # 8022A990 => cmpwi r0, 1
# region @ 8022B190 (4 bytes)
.data 0x8022B190 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022B190 => li r4, 0xFFFFFF00
# region @ 8022B1C0 (4 bytes)
.data 0x8022B1C0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022B1C0 => li r4, 0xFFFFFE80
# region @ 8022B1F0 (4 bytes)
.data 0x8022B1F0 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022B1F0 => li r4, 0xFFFFFDB0
# region @ 8022DE8C (4 bytes)
.data 0x8022DE8C # address
.data 0x00000004 # size
.data 0x60000000 # 8022DE8C => nop
# region @ 8022E5C0 (4 bytes)
.data 0x8022E5C0 # address
.data 0x00000004 # size
.data 0x41810630 # 8022E5C0 => bgt +0x00000630 /* 8022EBF0 */
# region @ 8022F8E4 (4 bytes)
.data 0x8022F8E4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022F8E4 => li r4, 0xFFFFFF00
# region @ 8022F914 (4 bytes)
.data 0x8022F914 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022F914 => li r4, 0xFFFFFE80
# region @ 8022F944 (4 bytes)
.data 0x8022F944 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022F944 => li r4, 0xFFFFFDB0
# region @ 802300F0 (4 bytes)
.data 0x802300F0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802300F0 => li r4, 0xFFFFFF00
# region @ 80230120 (4 bytes)
.data 0x80230120 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80230120 => li r4, 0xFFFFFE80
# region @ 80230150 (4 bytes)
.data 0x80230150 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80230150 => li r4, 0xFFFFFDB0
# region @ 802316F4 (4 bytes)
.data 0x802316F4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802316F4 => li r4, 0xFFFFFF00
# region @ 80231724 (4 bytes)
.data 0x80231724 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80231724 => li r4, 0xFFFFFE80
# region @ 80231754 (4 bytes)
.data 0x80231754 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80231754 => li r4, 0xFFFFFDB0
# region @ 80232464 (4 bytes)
.data 0x80232464 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80232464 => li r4, 0xFFFFFF00
# region @ 80232494 (4 bytes)
.data 0x80232494 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80232494 => li r4, 0xFFFFFE80
# region @ 802324C4 (4 bytes)
.data 0x802324C4 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802324C4 => li r4, 0xFFFFFDB0
# region @ 80232D58 (4 bytes)
.data 0x80232D58 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80232D58 => li r4, 0xFFFFFF00
# region @ 80232D90 (4 bytes)
.data 0x80232D90 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80232D90 => li r4, 0xFFFFFE80
# region @ 80232DC8 (4 bytes)
.data 0x80232DC8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80232DC8 => li r4, 0xFFFFFDB0
# region @ 80234E04 (4 bytes)
.data 0x80234E04 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80234E04 => li r4, 0xFFFFFF00
# region @ 80234E34 (4 bytes)
.data 0x80234E34 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80234E34 => li r4, 0xFFFFFE80
# region @ 80234E64 (4 bytes)
.data 0x80234E64 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80234E64 => li r4, 0xFFFFFDB0
# region @ 80237430 (4 bytes)
.data 0x80237430 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80237430 => li r4, 0xFFFFFF00
# region @ 8023746C (4 bytes)
.data 0x8023746C # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023746C => li r4, 0xFFFFFE80
# region @ 802374A8 (4 bytes)
.data 0x802374A8 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 802374A8 => li r4, 0xFFFFFDB0
# region @ 80237C08 (4 bytes)
.data 0x80237C08 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80237C08 => li r4, 0xFFFFFF00
# region @ 80237C38 (4 bytes)
.data 0x80237C38 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80237C38 => li r4, 0xFFFFFE80
# region @ 80237C68 (4 bytes)
.data 0x80237C68 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80237C68 => li r4, 0xFFFFFDB0
# region @ 8023861C (4 bytes)
.data 0x8023861C # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023861C => li r4, 0xFFFFFF00
# region @ 8023864C (4 bytes)
.data 0x8023864C # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023864C => li r4, 0xFFFFFE80
# region @ 8023867C (4 bytes)
.data 0x8023867C # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023867C => li r4, 0xFFFFFDB0
# region @ 80238FF4 (4 bytes)
.data 0x80238FF4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80238FF4 => li r4, 0xFFFFFF00
# region @ 80239024 (4 bytes)
.data 0x80239024 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80239024 => li r4, 0xFFFFFE80
# region @ 80239054 (4 bytes)
.data 0x80239054 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80239054 => li r4, 0xFFFFFDB0
# region @ 8023C924 (4 bytes)
.data 0x8023C924 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023C924 => li r4, 0xFFFFFF00
# region @ 8023C954 (4 bytes)
.data 0x8023C954 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023C954 => li r4, 0xFFFFFE80
# region @ 8023C984 (4 bytes)
.data 0x8023C984 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023C984 => li r4, 0xFFFFFDB0
# region @ 802519A4 (4 bytes)
.data 0x802519A4 # address
.data 0x00000004 # size
.data 0x60000000 # 802519A4 => nop
# region @ 80269898 (4 bytes)
.data 0x80269898 # address
.data 0x00000004 # size
.data 0x60000000 # 80269898 => nop
# region @ 8026F548 (4 bytes)
.data 0x8026F548 # address
.data 0x00000004 # size
.data 0x3884AAFA # 8026F548 => subi r4, r4, 0x5506
# region @ 8026F65C (4 bytes)
.data 0x8026F65C # address
.data 0x00000004 # size
.data 0x3863AAFA # 8026F65C => subi r3, r3, 0x5506
# region @ 8026F6E4 (4 bytes)
.data 0x8026F6E4 # address
.data 0x00000004 # size
.data 0x3883AAFA # 8026F6E4 => subi r4, r3, 0x5506
# region @ 802BD2C0 (4 bytes)
.data 0x802BD2C0 # address
.data 0x00000004 # size
.data 0x4BD506C0 # 802BD2C0 => b -0x002AF940 /* 8000D980 */
# region @ 802FDB6C (4 bytes)
.data 0x802FDB6C # address
.data 0x00000004 # size
.data 0x2C030001 # 802FDB6C => cmpwi r3, 1
# region @ 803037D0 (28 bytes)
.data 0x803037D0 # address
.data 0x0000001C # size
.data 0x48000020 # 803037D0 => b +0x00000020 /* 803037F0 */
.data 0x3863A830 # 803037D4 => subi r3, r3, 0x57D0
.data 0x800DB9B4 # 803037D8 => lwz r0, [r13 - 0x464C]
.data 0x2C000023 # 803037DC => cmpwi r0, 35
.data 0x40820008 # 803037E0 => bne +0x00000008 /* 803037E8 */
.data 0x3863FB28 # 803037E4 => subi r3, r3, 0x04D8
.data 0x4800008C # 803037E8 => b +0x0000008C /* 80303874 */
# region @ 80303870 (4 bytes)
.data 0x80303870 # address
.data 0x00000004 # size
.data 0x4BFFFF64 # 80303870 => b -0x0000009C /* 803037D4 */
# region @ 8033739C (4 bytes)
.data 0x8033739C # address
.data 0x00000004 # size
.data 0x4BCD6604 # 8033739C => b -0x003299FC /* 8000D9A0 */
# region @ 80358074 (4 bytes)
.data 0x80358074 # address
.data 0x00000004 # size
.data 0x388001E8 # 80358074 => li r4, 0x01E8
# region @ 80358098 (4 bytes)
.data 0x80358098 # address
.data 0x00000004 # size
.data 0x4BCB6149 # 80358098 => bl -0x00349EB8 /* 8000E1E0 */
# region @ 80358108 (4 bytes)
.data 0x80358108 # address
.data 0x00000004 # size
.data 0x388001E8 # 80358108 => li r4, 0x01E8
# region @ 80358118 (4 bytes)
.data 0x80358118 # address
.data 0x00000004 # size
.data 0x4BCB60C9 # 80358118 => bl -0x00349F38 /* 8000E1E0 */
# region @ 804B90B8 (8 bytes)
.data 0x804B90B8 # address
.data 0x00000008 # size
.data 0x70808080 # 804B90B8 => andi. r0, r4, 0x8080
.data 0x60707070 # 804B90BC => ori r16, r3, 0x7070
# region @ 804CC90C (4 bytes)
.data 0x804CC90C # address
.data 0x00000004 # size
.data 0x0000001E # 804CC90C => .invalid
# region @ 804CC964 (4 bytes)
.data 0x804CC964 # address
.data 0x00000004 # size
.data 0x00000028 # 804CC964 => .invalid
# region @ 804CC990 (4 bytes)
.data 0x804CC990 # address
.data 0x00000004 # size
.data 0x00000032 # 804CC990 => .invalid
# region @ 804CC9BC (4 bytes)
.data 0x804CC9BC # address
.data 0x00000004 # size
.data 0x0000003C # 804CC9BC => .invalid
# region @ 804CC9CC (4 bytes)
.data 0x804CC9CC # address
.data 0x00000004 # size
.data 0x0018003C # 804CC9CC => .invalid
# region @ 804CCC24 (4 bytes)
.data 0x804CCC24 # address
.data 0x00000004 # size
.data 0x00000028 # 804CCC24 => .invalid
# region @ 804D1580 (4 bytes)
.data 0x804D1580 # address
.data 0x00000004 # size
.data 0xFF0074EE # 804D1580 => fsel f24, f0, f14, f19
# region @ 805DB1AC (4 bytes)
.data 0x805DB1AC # address
.data 0x00000004 # size
.data 0x435C0000 # 805DB1AC => bc 26, 28, +0x00000000 /* 805DB1AC */
# region @ 805DCE48 (4 bytes)
.data 0x805DCE48 # address
.data 0x00000004 # size
.data 0x46AFC800 # 805DCE48 => .invalid sc
# region @ 805DD0E8 (4 bytes)
.data 0x805DD0E8 # address
.data 0x00000004 # size
.data 0x43480000 # 805DD0E8 => bc 26, 8, +0x00000000 /* 805DD0E8 */
# end sentinel
.data 0x00000000 # address
.data 0x00000000 # size
@@ -1,552 +0,0 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
# region @ 8000B088 (88 bytes)
.data 0x8000B088 # address
.data 0x00000058 # size
.data 0x7FA3EB78 # 8000B088 => mr r3, r29
.data 0x38800000 # 8000B08C => li r4, 0x0000
.data 0x481AF17D # 8000B090 => bl +0x001AF17C /* 801BA20C */
.data 0x7FA3EB78 # 8000B094 => mr r3, r29
.data 0x481AF44C # 8000B098 => b +0x001AF44C /* 801BA4E4 */
.data 0x881F0000 # 8000B09C => lbz r0, [r31]
.data 0x28090001 # 8000B0A0 => cmplwi r9, 1
.data 0x4082000C # 8000B0A4 => bne +0x0000000C /* 8000B0B0 */
.data 0x881F0001 # 8000B0A8 => lbz r0, [r31 + 0x0001]
.data 0x3BFF0002 # 8000B0AC => addi r31, r31, 0x0002
.data 0x48100C44 # 8000B0B0 => b +0x00100C44 /* 8010BCF4 */
.data 0x39200000 # 8000B0B4 => li r9, 0x0000
.data 0x48100BD5 # 8000B0B8 => bl +0x00100BD4 /* 8010BC8C */
.data 0x7F43D378 # 8000B0BC => mr r3, r26
.data 0x7F64DB78 # 8000B0C0 => mr r4, r27
.data 0x7F85E378 # 8000B0C4 => mr r5, r28
.data 0x7FA6EB78 # 8000B0C8 => mr r6, r29
.data 0x7FC7F378 # 8000B0CC => mr r7, r30
.data 0x7FE8FB78 # 8000B0D0 => mr r8, r31
.data 0x39200001 # 8000B0D4 => li r9, 0x0001
.data 0x48100BB5 # 8000B0D8 => bl +0x00100BB4 /* 8010BC8C */
.data 0x48103040 # 8000B0DC => b +0x00103040 /* 8010E11C */
# region @ 8000B5C8 (20 bytes)
.data 0x8000B5C8 # address
.data 0x00000014 # size
.data 0x80630098 # 8000B5C8 => lwz r3, [r3 + 0x0098]
.data 0x483D7BE1 # 8000B5CC => bl +0x003D7BE0 /* 803E31AC */
.data 0x807F042C # 8000B5D0 => lwz r3, [r31 + 0x042C]
.data 0x809F0430 # 8000B5D4 => lwz r4, [r31 + 0x0430]
.data 0x48179274 # 8000B5D8 => b +0x00179274 /* 8018484C */
# region @ 8000BBD0 (32 bytes)
.data 0x8000BBD0 # address
.data 0x00000020 # size
.data 0x809F0370 # 8000BBD0 => lwz r4, [r31 + 0x0370]
.data 0x3884FC00 # 8000BBD4 => subi r4, r4, 0x0400
.data 0x909F0370 # 8000BBD8 => stw [r31 + 0x0370], r4
.data 0x807F0014 # 8000BBDC => lwz r3, [r31 + 0x0014]
.data 0x28030000 # 8000BBE0 => cmplwi r3, 0
.data 0x41820008 # 8000BBE4 => beq +0x00000008 /* 8000BBEC */
.data 0x90830060 # 8000BBE8 => stw [r3 + 0x0060], r4
.data 0x48165A0C # 8000BBEC => b +0x00165A0C /* 801715F8 */
# region @ 8000C3F8 (124 bytes)
.data 0x8000C3F8 # address
.data 0x0000007C # size
.data 0x28040000 # 8000C3F8 => cmplwi r4, 0
.data 0x4D820020 # 8000C3FC => beqlr
.data 0x9421FFF0 # 8000C400 => stwu [r1 - 0x0010], r1
.data 0x481ADE0C # 8000C404 => b +0x001ADE0C /* 801BA210 */
.data 0x9421FFE0 # 8000C408 => stwu [r1 - 0x0020], r1
.data 0x7C0802A6 # 8000C40C => mflr r0
.data 0x90010024 # 8000C410 => stw [r1 + 0x0024], r0
.data 0xBF410008 # 8000C414 => stmw [r1 + 0x0008], r26
.data 0x7C7F1B78 # 8000C418 => mr r31, r3
.data 0x4BFFFFDD # 8000C41C => bl -0x00000024 /* 8000C3F8 */
.data 0x3BC00000 # 8000C420 => li r30, 0x0000
.data 0x3BBF0D04 # 8000C424 => addi r29, r31, 0x0D04
.data 0x837F032C # 8000C428 => lwz r27, [r31 + 0x032C]
.data 0x839D0000 # 8000C42C => lwz r28, [r29]
.data 0x7F83E379 # 8000C430 => mr. r3, r28
.data 0x41820018 # 8000C434 => beq +0x00000018 /* 8000C44C */
.data 0x38800001 # 8000C438 => li r4, 0x0001
.data 0x480FEE5D # 8000C43C => bl +0x000FEE5C /* 8010B298 */
.data 0x7F83E378 # 8000C440 => mr r3, r28
.data 0x38800001 # 8000C444 => li r4, 0x0001
.data 0x480FEFCD # 8000C448 => bl +0x000FEFCC /* 8010B414 */
.data 0x3BBD0004 # 8000C44C => addi r29, r29, 0x0004
.data 0x3BDE0001 # 8000C450 => addi r30, r30, 0x0001
.data 0x2C1E000D # 8000C454 => cmpwi r30, 13
.data 0x4180FFD4 # 8000C458 => blt -0x0000002C /* 8000C42C */
.data 0x937F032C # 8000C45C => stw [r31 + 0x032C], r27
.data 0xBB410008 # 8000C460 => lmw r26, [r1 + 0x0008]
.data 0x80010024 # 8000C464 => lwz r0, [r1 + 0x0024]
.data 0x7C0803A6 # 8000C468 => mtlr r0
.data 0x38210020 # 8000C46C => addi r1, r1, 0x0020
.data 0x4E800020 # 8000C470 => blr
# region @ 8000C640 (20 bytes)
.data 0x8000C640 # address
.data 0x00000014 # size
.data 0x54800673 # 8000C640 => rlwinm. r0, r4, 0, 25, 25
.data 0x41820008 # 8000C644 => beq +0x00000008 /* 8000C64C */
.data 0x38800000 # 8000C648 => li r4, 0x0000
.data 0x38040009 # 8000C64C => addi r0, r4, 0x0009
.data 0x4810CA30 # 8000C650 => b +0x0010CA30 /* 80119080 */
# region @ 8000C6D0 (32 bytes)
.data 0x8000C6D0 # address
.data 0x00000020 # size
.data 0x38000001 # 8000C6D0 => li r0, 0x0001
.data 0x901D0054 # 8000C6D4 => stw [r29 + 0x0054], r0
.data 0x807D0024 # 8000C6D8 => lwz r3, [r29 + 0x0024]
.data 0x48211B90 # 8000C6DC => b +0x00211B90 /* 8021E26C */
.data 0x38000001 # 8000C6E0 => li r0, 0x0001
.data 0x901F0378 # 8000C6E4 => stw [r31 + 0x0378], r0
.data 0x807F0024 # 8000C6E8 => lwz r3, [r31 + 0x0024]
.data 0x48215040 # 8000C6EC => b +0x00215040 /* 8022172C */
# region @ 8000C8A0 (20 bytes)
.data 0x8000C8A0 # address
.data 0x00000014 # size
.data 0x1C00000A # 8000C8A0 => mulli r0, r0, 10
.data 0x57E407BD # 8000C8A4 => rlwinm. r4, r31, 0, 30, 30
.data 0x41820008 # 8000C8A8 => beq +0x00000008 /* 8000C8B0 */
.data 0x7FA00734 # 8000C8AC => extsh r0, r29
.data 0x48106138 # 8000C8B0 => b +0x00106138 /* 801129E8 */
# region @ 8000C8C0 (16 bytes)
.data 0x8000C8C0 # address
.data 0x00000010 # size
.data 0x7000000F # 8000C8C0 => andi. r0, r0, 0x000F
.data 0x7000004F # 8000C8C4 => andi. r0, r0, 0x004F
.data 0x2C000004 # 8000C8C8 => cmpwi r0, 4
.data 0x4E800020 # 8000C8CC => blr
# region @ 8000D980 (20 bytes)
.data 0x8000D980 # address
.data 0x00000014 # size
.data 0x807C0000 # 8000D980 => lwz r3, [r28]
.data 0x2C030013 # 8000D984 => cmpwi r3, 19
.data 0x40820008 # 8000D988 => bne +0x00000008 /* 8000D990 */
.data 0x38600002 # 8000D98C => li r3, 0x0002
.data 0x482AF27C # 8000D990 => b +0x002AF27C /* 802BCC0C */
# region @ 8000D9A0 (24 bytes)
.data 0x8000D9A0 # address
.data 0x00000018 # size
.data 0xC042FC88 # 8000D9A0 => lfs f2, [r2 - 0x0378]
.data 0x807E0030 # 8000D9A4 => lwz r3, [r30 + 0x0030]
.data 0x70630020 # 8000D9A8 => andi. r3, r3, 0x0020
.data 0x41820008 # 8000D9AC => beq +0x00000008 /* 8000D9B4 */
.data 0xC042FCA0 # 8000D9B0 => lfs f2, [r2 - 0x0360]
.data 0x48329004 # 8000D9B4 => b +0x00329004 /* 803369B8 */
# region @ 8000E1E0 (28 bytes)
.data 0x8000E1E0 # address
.data 0x0000001C # size
.data 0x7FC802A6 # 8000E1E0 => mflr r30
.data 0x38A00000 # 8000E1E4 => li r5, 0x0000
.data 0x38C0001E # 8000E1E8 => li r6, 0x001E
.data 0x38E00040 # 8000E1EC => li r7, 0x0040
.data 0x4807869D # 8000E1F0 => bl +0x0007869C /* 8008688C */
.data 0x7FC803A6 # 8000E1F4 => mtlr r30
.data 0x4E800020 # 8000E1F8 => blr
# region @ 800130C4 (4 bytes)
.data 0x800130C4 # address
.data 0x00000004 # size
.data 0x4BFFFCC0 # 800130C4 => b -0x00000340 /* 80012D84 */
# region @ 80014334 (4 bytes)
.data 0x80014334 # address
.data 0x00000004 # size
.data 0x4BFF858D # 80014334 => bl -0x00007A74 /* 8000C8C0 */
# region @ 80015D5C (4 bytes)
.data 0x80015D5C # address
.data 0x00000004 # size
.data 0x4BFF6B69 # 80015D5C => bl -0x00009498 /* 8000C8C4 */
# region @ 80091914 (8 bytes)
.data 0x80091914 # address
.data 0x00000008 # size
.data 0x4800024D # 80091914 => bl +0x0000024C /* 80091B60 */
.data 0xB3C3032C # 80091918 => sth [r3 + 0x032C], r30
# region @ 800BCB58 (4 bytes)
.data 0x800BCB58 # address
.data 0x00000004 # size
.data 0x48000010 # 800BCB58 => b +0x00000010 /* 800BCB68 */
# region @ 80104EA4 (4 bytes)
.data 0x80104EA4 # address
.data 0x00000004 # size
.data 0x4182000C # 80104EA4 => beq +0x0000000C /* 80104EB0 */
# region @ 801077D4 (4 bytes)
.data 0x801077D4 # address
.data 0x00000004 # size
.data 0x4800000C # 801077D4 => b +0x0000000C /* 801077E0 */
# region @ 801077E8 (4 bytes)
.data 0x801077E8 # address
.data 0x00000004 # size
.data 0x7C030378 # 801077E8 => mr r3, r0
# region @ 8010BCF0 (4 bytes)
.data 0x8010BCF0 # address
.data 0x00000004 # size
.data 0x4BEFF3AC # 8010BCF0 => b -0x00100C54 /* 8000B09C */
# region @ 8010E118 (4 bytes)
.data 0x8010E118 # address
.data 0x00000004 # size
.data 0x4BEFCF9C # 8010E118 => b -0x00103064 /* 8000B0B4 */
# region @ 801129E4 (4 bytes)
.data 0x801129E4 # address
.data 0x00000004 # size
.data 0x4BEF9EBC # 801129E4 => b -0x00106144 /* 8000C8A0 */
# region @ 8011470C (4 bytes)
.data 0x8011470C # address
.data 0x00000004 # size
.data 0x38000012 # 8011470C => li r0, 0x0012
# region @ 8011894C (4 bytes)
.data 0x8011894C # address
.data 0x00000004 # size
.data 0x88040016 # 8011894C => lbz r0, [r4 + 0x0016]
# region @ 80118958 (4 bytes)
.data 0x80118958 # address
.data 0x00000004 # size
.data 0x88040017 # 80118958 => lbz r0, [r4 + 0x0017]
# region @ 8011907C (4 bytes)
.data 0x8011907C # address
.data 0x00000004 # size
.data 0x4BEF35C4 # 8011907C => b -0x0010CA3C /* 8000C640 */
# region @ 8011CE54 (12 bytes)
.data 0x8011CE54 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CE54 => mr r3, r0
.data 0x3863FFFF # 8011CE58 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CE5C => b -0x00000018 /* 8011CE44 */
# region @ 8011CF10 (12 bytes)
.data 0x8011CF10 # address
.data 0x0000000C # size
.data 0x7C030378 # 8011CF10 => mr r3, r0
.data 0x3863FFFF # 8011CF14 => subi r3, r3, 0x0001
.data 0x4BFFFFE8 # 8011CF18 => b -0x00000018 /* 8011CF00 */
# region @ 8011CF60 (12 bytes)
.data 0x8011CF60 # address
.data 0x0000000C # size
.data 0x7C040378 # 8011CF60 => mr r4, r0
.data 0x3884FFFF # 8011CF64 => subi r4, r4, 0x0001
.data 0x4BFFFFE8 # 8011CF68 => b -0x00000018 /* 8011CF50 */
# region @ 80166CC4 (8 bytes)
.data 0x80166CC4 # address
.data 0x00000008 # size
.data 0x3C604005 # 80166CC4 => lis r3, 0x4005
.data 0x4800009C # 80166CC8 => b +0x0000009C /* 80166D64 */
# region @ 80166D60 (4 bytes)
.data 0x80166D60 # address
.data 0x00000004 # size
.data 0x4800001C # 80166D60 => b +0x0000001C /* 80166D7C */
# region @ 801715F4 (4 bytes)
.data 0x801715F4 # address
.data 0x00000004 # size
.data 0x4BE9A5DC # 801715F4 => b -0x00165A24 /* 8000BBD0 */
# region @ 80171614 (4 bytes)
.data 0x80171614 # address
.data 0x00000004 # size
.data 0x60800420 # 80171614 => ori r0, r4, 0x0420
# region @ 80184848 (4 bytes)
.data 0x80184848 # address
.data 0x00000004 # size
.data 0x4BE86D80 # 80184848 => b -0x00179280 /* 8000B5C8 */
# region @ 80184888 (4 bytes)
.data 0x80184888 # address
.data 0x00000004 # size
.data 0x60000000 # 80184888 => nop
# region @ 8018A418 (4 bytes)
.data 0x8018A418 # address
.data 0x00000004 # size
.data 0x60000000 # 8018A418 => nop
# region @ 80193D9C (4 bytes)
.data 0x80193D9C # address
.data 0x00000004 # size
.data 0x60000000 # 80193D9C => nop
# region @ 801BA20C (4 bytes)
.data 0x801BA20C # address
.data 0x00000004 # size
.data 0x4BE521FC # 801BA20C => b -0x001ADE04 /* 8000C408 */
# region @ 801BA4E0 (4 bytes)
.data 0x801BA4E0 # address
.data 0x00000004 # size
.data 0x4BE50BA8 # 801BA4E0 => b -0x001AF458 /* 8000B088 */
# region @ 801C694C (4 bytes)
.data 0x801C694C # address
.data 0x00000004 # size
.data 0x389F02FC # 801C694C => addi r4, r31, 0x02FC
# region @ 801CACCC (4 bytes)
.data 0x801CACCC # address
.data 0x00000004 # size
.data 0x48000010 # 801CACCC => b +0x00000010 /* 801CACDC */
# region @ 8021E268 (4 bytes)
.data 0x8021E268 # address
.data 0x00000004 # size
.data 0x4BDEE468 # 8021E268 => b -0x00211B98 /* 8000C6D0 */
# region @ 80221728 (4 bytes)
.data 0x80221728 # address
.data 0x00000004 # size
.data 0x4BDEAFB8 # 80221728 => b -0x00215048 /* 8000C6E0 */
# region @ 8022A55C (4 bytes)
.data 0x8022A55C # address
.data 0x00000004 # size
.data 0x2C000001 # 8022A55C => cmpwi r0, 1
# region @ 8022AD5C (4 bytes)
.data 0x8022AD5C # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022AD5C => li r4, 0xFFFFFF00
# region @ 8022AD8C (4 bytes)
.data 0x8022AD8C # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022AD8C => li r4, 0xFFFFFE80
# region @ 8022ADBC (4 bytes)
.data 0x8022ADBC # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022ADBC => li r4, 0xFFFFFDB0
# region @ 8022DA58 (4 bytes)
.data 0x8022DA58 # address
.data 0x00000004 # size
.data 0x60000000 # 8022DA58 => nop
# region @ 8022E18C (4 bytes)
.data 0x8022E18C # address
.data 0x00000004 # size
.data 0x41810630 # 8022E18C => bgt +0x00000630 /* 8022E7BC */
# region @ 8022F4B0 (4 bytes)
.data 0x8022F4B0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022F4B0 => li r4, 0xFFFFFF00
# region @ 8022F4E0 (4 bytes)
.data 0x8022F4E0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022F4E0 => li r4, 0xFFFFFE80
# region @ 8022F510 (4 bytes)
.data 0x8022F510 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022F510 => li r4, 0xFFFFFDB0
# region @ 8022FCBC (4 bytes)
.data 0x8022FCBC # address
.data 0x00000004 # size
.data 0x3880FF00 # 8022FCBC => li r4, 0xFFFFFF00
# region @ 8022FCEC (4 bytes)
.data 0x8022FCEC # address
.data 0x00000004 # size
.data 0x3880FE80 # 8022FCEC => li r4, 0xFFFFFE80
# region @ 8022FD1C (4 bytes)
.data 0x8022FD1C # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8022FD1C => li r4, 0xFFFFFDB0
# region @ 802312C0 (4 bytes)
.data 0x802312C0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802312C0 => li r4, 0xFFFFFF00
# region @ 802312F0 (4 bytes)
.data 0x802312F0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 802312F0 => li r4, 0xFFFFFE80
# region @ 80231320 (4 bytes)
.data 0x80231320 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80231320 => li r4, 0xFFFFFDB0
# region @ 80232030 (4 bytes)
.data 0x80232030 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80232030 => li r4, 0xFFFFFF00
# region @ 80232060 (4 bytes)
.data 0x80232060 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80232060 => li r4, 0xFFFFFE80
# region @ 80232090 (4 bytes)
.data 0x80232090 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80232090 => li r4, 0xFFFFFDB0
# region @ 80232924 (4 bytes)
.data 0x80232924 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80232924 => li r4, 0xFFFFFF00
# region @ 8023295C (4 bytes)
.data 0x8023295C # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023295C => li r4, 0xFFFFFE80
# region @ 80232994 (4 bytes)
.data 0x80232994 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80232994 => li r4, 0xFFFFFDB0
# region @ 802349D0 (4 bytes)
.data 0x802349D0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802349D0 => li r4, 0xFFFFFF00
# region @ 80234A00 (4 bytes)
.data 0x80234A00 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80234A00 => li r4, 0xFFFFFE80
# region @ 80234A30 (4 bytes)
.data 0x80234A30 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80234A30 => li r4, 0xFFFFFDB0
# region @ 80236FFC (4 bytes)
.data 0x80236FFC # address
.data 0x00000004 # size
.data 0x3880FF00 # 80236FFC => li r4, 0xFFFFFF00
# region @ 80237038 (4 bytes)
.data 0x80237038 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80237038 => li r4, 0xFFFFFE80
# region @ 80237074 (4 bytes)
.data 0x80237074 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80237074 => li r4, 0xFFFFFDB0
# region @ 802377D4 (4 bytes)
.data 0x802377D4 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802377D4 => li r4, 0xFFFFFF00
# region @ 80237804 (4 bytes)
.data 0x80237804 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80237804 => li r4, 0xFFFFFE80
# region @ 80237834 (4 bytes)
.data 0x80237834 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80237834 => li r4, 0xFFFFFDB0
# region @ 802381E8 (4 bytes)
.data 0x802381E8 # address
.data 0x00000004 # size
.data 0x3880FF00 # 802381E8 => li r4, 0xFFFFFF00
# region @ 80238218 (4 bytes)
.data 0x80238218 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80238218 => li r4, 0xFFFFFE80
# region @ 80238248 (4 bytes)
.data 0x80238248 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80238248 => li r4, 0xFFFFFDB0
# region @ 80238BC0 (4 bytes)
.data 0x80238BC0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 80238BC0 => li r4, 0xFFFFFF00
# region @ 80238BF0 (4 bytes)
.data 0x80238BF0 # address
.data 0x00000004 # size
.data 0x3880FE80 # 80238BF0 => li r4, 0xFFFFFE80
# region @ 80238C20 (4 bytes)
.data 0x80238C20 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 80238C20 => li r4, 0xFFFFFDB0
# region @ 8023C4F0 (4 bytes)
.data 0x8023C4F0 # address
.data 0x00000004 # size
.data 0x3880FF00 # 8023C4F0 => li r4, 0xFFFFFF00
# region @ 8023C520 (4 bytes)
.data 0x8023C520 # address
.data 0x00000004 # size
.data 0x3880FE80 # 8023C520 => li r4, 0xFFFFFE80
# region @ 8023C550 (4 bytes)
.data 0x8023C550 # address
.data 0x00000004 # size
.data 0x3880FDB0 # 8023C550 => li r4, 0xFFFFFDB0
# region @ 802514B0 (4 bytes)
.data 0x802514B0 # address
.data 0x00000004 # size
.data 0x60000000 # 802514B0 => nop
# region @ 802693A4 (4 bytes)
.data 0x802693A4 # address
.data 0x00000004 # size
.data 0x60000000 # 802693A4 => nop
# region @ 8026EF44 (4 bytes)
.data 0x8026EF44 # address
.data 0x00000004 # size
.data 0x3884AAFA # 8026EF44 => subi r4, r4, 0x5506
# region @ 8026F058 (4 bytes)
.data 0x8026F058 # address
.data 0x00000004 # size
.data 0x3863AAFA # 8026F058 => subi r3, r3, 0x5506
# region @ 8026F0E0 (4 bytes)
.data 0x8026F0E0 # address
.data 0x00000004 # size
.data 0x3883AAFA # 8026F0E0 => subi r4, r3, 0x5506
# region @ 802BCC08 (4 bytes)
.data 0x802BCC08 # address
.data 0x00000004 # size
.data 0x4BD50D78 # 802BCC08 => b -0x002AF288 /* 8000D980 */
# region @ 802FD100 (4 bytes)
.data 0x802FD100 # address
.data 0x00000004 # size
.data 0x2C030001 # 802FD100 => cmpwi r3, 1
# region @ 80302D64 (28 bytes)
.data 0x80302D64 # address
.data 0x0000001C # size
.data 0x48000020 # 80302D64 => b +0x00000020 /* 80302D84 */
.data 0x3863A830 # 80302D68 => subi r3, r3, 0x57D0
.data 0x800DBA04 # 80302D6C => lwz r0, [r13 - 0x45FC]
.data 0x2C000023 # 80302D70 => cmpwi r0, 35
.data 0x40820008 # 80302D74 => bne +0x00000008 /* 80302D7C */
.data 0x3863FB28 # 80302D78 => subi r3, r3, 0x04D8
.data 0x4800008C # 80302D7C => b +0x0000008C /* 80302E08 */
# region @ 80302E04 (4 bytes)
.data 0x80302E04 # address
.data 0x00000004 # size
.data 0x4BFFFF64 # 80302E04 => b -0x0000009C /* 80302D68 */
# region @ 803369B4 (4 bytes)
.data 0x803369B4 # address
.data 0x00000004 # size
.data 0x4BCD6FEC # 803369B4 => b -0x00329014 /* 8000D9A0 */
# region @ 80357834 (4 bytes)
.data 0x80357834 # address
.data 0x00000004 # size
.data 0x388001E8 # 80357834 => li r4, 0x01E8
# region @ 80357858 (4 bytes)
.data 0x80357858 # address
.data 0x00000004 # size
.data 0x4BCB6989 # 80357858 => bl -0x00349678 /* 8000E1E0 */
# region @ 803578C8 (4 bytes)
.data 0x803578C8 # address
.data 0x00000004 # size
.data 0x388001E8 # 803578C8 => li r4, 0x01E8
# region @ 803578D8 (4 bytes)
.data 0x803578D8 # address
.data 0x00000004 # size
.data 0x4BCB6909 # 803578D8 => bl -0x003496F8 /* 8000E1E0 */
# region @ 804B8E10 (8 bytes)
.data 0x804B8E10 # address
.data 0x00000008 # size
.data 0x70808080 # 804B8E10 => andi. r0, r4, 0x8080
.data 0x60707070 # 804B8E14 => ori r16, r3, 0x7070
# region @ 804CC5D4 (4 bytes)
.data 0x804CC5D4 # address
.data 0x00000004 # size
.data 0x0000001E # 804CC5D4 => .invalid
# region @ 804CC62C (4 bytes)
.data 0x804CC62C # address
.data 0x00000004 # size
.data 0x00000028 # 804CC62C => .invalid
# region @ 804CC658 (4 bytes)
.data 0x804CC658 # address
.data 0x00000004 # size
.data 0x00000032 # 804CC658 => .invalid
# region @ 804CC684 (4 bytes)
.data 0x804CC684 # address
.data 0x00000004 # size
.data 0x0000003C # 804CC684 => .invalid
# region @ 804CC694 (4 bytes)
.data 0x804CC694 # address
.data 0x00000004 # size
.data 0x0018003C # 804CC694 => .invalid
# region @ 804CC8EC (4 bytes)
.data 0x804CC8EC # address
.data 0x00000004 # size
.data 0x00000028 # 804CC8EC => .invalid
# region @ 804D1248 (4 bytes)
.data 0x804D1248 # address
.data 0x00000004 # size
.data 0xFF0074EE # 804D1248 => fsel f24, f0, f14, f19
# region @ 805D6CF4 (4 bytes)
.data 0x805D6CF4 # address
.data 0x00000004 # size
.data 0x435C0000 # 805D6CF4 => bc 26, 28, +0x00000000 /* 805D6CF4 */
# region @ 805D8990 (4 bytes)
.data 0x805D8990 # address
.data 0x00000004 # size
.data 0x46AFC800 # 805D8990 => .invalid sc
# region @ 805D8C30 (4 bytes)
.data 0x805D8C30 # address
.data 0x00000004 # size
.data 0x43480000 # 805D8C30 => bc 26, 8, +0x00000000 /* 805D8C30 */
# end sentinel
.data 0x00000000 # address
.data 0x00000000 # size
@@ -0,0 +1,590 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
.versions 3OE0 3OE1 3OJ2
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
.data 0x8000B088
.data 0x00000058
.data 0x7FA3EB78
.data 0x38800000
.data <VERS 0x481AEB11 0x481AEB11 0x481AE725>
.data 0x7FA3EB78
.data <VERS 0x481AEDE0 0x481AEDE0 0x481AE9F4>
.data 0x881F0000
.data 0x28090001
.data 0x4082000C
.data 0x881F0001
.data 0x3BFF0002
.data <VERS 0x48100B68 0x48100B68 0x481008C4>
.data 0x39200000
.data <VERS 0x48100AF9 0x48100AF9 0x48100855>
.data 0x7F43D378
.data 0x7F64DB78
.data 0x7F85E378
.data 0x7FA6EB78
.data 0x7FC7F378
.data 0x7FE8FB78
.data 0x39200001
.data <VERS 0x48100AD9 0x48100AD9 0x48100835>
.data <VERS 0x48102F64 0x48102F64 0x48102CC0>
.data 0x8000B5C8
.data 0x00000014
.data 0x80630098
.data <VERS 0x483D5999 0x483D59F1 0x483D46F5>
.data 0x807F042C
.data 0x809F0430
.data <VERS 0x48178C7C 0x48178C7C 0x481788C0>
.data 0x8000BBD0
.data 0x00000020
.data 0x809F0370
.data 0x3884FC00
.data 0x909F0370
.data 0x807F0014
.data 0x28030000
.data 0x41820008
.data 0x90830060
.data <VERS 0x48165428 0x48165428 0x4816506C>
.data 0x8000C3F8
.data 0x0000007C
.data 0x28040000
.data 0x4D820020
.data 0x9421FFF0
.data <VERS 0x481AD7A0 0x481AD7A0 0x481AD3B4>
.data 0x9421FFE0
.data 0x7C0802A6
.data 0x90010024
.data 0xBF410008
.data 0x7C7F1B78
.data 0x4BFFFFDD
.data 0x3BC00000
.data 0x3BBF0D04
.data 0x837F032C
.data 0x839D0000
.data 0x7F83E379
.data 0x41820018
.data 0x38800001
.data <VERS 0x480FED81 0x480FED81 0x480FEADD>
.data 0x7F83E378
.data 0x38800001
.data <VERS 0x480FEEF1 0x480FEEF1 0x480FEC4D>
.data 0x3BBD0004
.data 0x3BDE0001
.data 0x2C1E000D
.data 0x4180FFD4
.data 0x937F032C
.data 0xBB410008
.data 0x80010024
.data 0x7C0803A6
.data 0x38210020
.data 0x4E800020
.data 0x8000C640
.data 0x00000014
.data 0x54800673
.data 0x41820008
.data 0x38800000
.data 0x38040009
.data <VERS 0x4810C938 0x4810C938 0x4810C694>
.data 0x8000C6D0
.data 0x00000020
.data 0x38000001
.data 0x901D0054
.data 0x807D0024
.data <VERS 0x48211244 0x48211244 0x482109C0>
.data 0x38000001
.data 0x901F0378
.data 0x807F0024
.data <VERS 0x482146F4 0x482146F4 0x48165AA0>
.data 0x8000C8A0
.data 0x00000014
.data 0x1C00000A
.data 0x57E407BD
.data 0x41820008
.data 0x7FA00734
.data <VERS 0x4810605C 0x4810605C 0x48105DB8>
.data 0x8000C8C0
.data 0x00000010
.data 0x7000000F
.data 0x7000004F
.data 0x2C000004
.data 0x4E800020
.data 0x8000D980
.data 0x00000014
.data 0x807C0000
.data 0x2C030013
.data 0x40820008
.data 0x38600002
.data <VERS 0x482AE568 0x482AE5AC 0x482ADB24>
.data 0x8000D9A0
.data 0x00000018
.data <VERS 0xC042FC88 0xC042FC88 0xC042FC78>
.data 0x807E0030
.data 0x70630020
.data 0x41820008
.data <VERS 0xC042FCA0 0xC042FCA0 0xC042FC90>
.data <VERS 0x483280A0 0x483280E4 0x483276B0>
.data 0x8000E1E0
.data 0x0000001C
.data 0x7FC802A6
.data 0x38A00000
.data 0x38C0001E
.data 0x38E00040
.data <VERS 0x4807853D 0x4807853D 0x480782B1>
.data 0x7FC803A6
.data 0x4E800020
.data <VERS 0x80013084 0x80013084 0x8001306C>
.data 0x00000004
.data 0x4BFFFCC0
.data <VERS 0x800142F4 0x800142F4 0x800142DC>
.data 0x00000004
.data <VERS 0x4BFF85CD 0x4BFF85CD 0x4BFF85E5>
.data <VERS 0x80015D1C 0x80015D1C 0x80015D04>
.data 0x00000004
.data <VERS 0x4BFF6BA9 0x4BFF6BA9 0x4BFF6BC1>
.data <VERS 0x800917B4 0x800917B4 0x80091528>
.data 0x00000008
.data 0x4800024D
.data 0xB3C3032C
.data <VERS 0x800BC9E8 0x800BC9E8 0x800BC750>
.data 0x00000004
.data 0x48000010
.data <VERS 0x80101EB8 0x80101EB8 0x80101C14>
.data 0x00000004
.data 0x60000000
.data <VERS 0x80104DEC 0x80104DEC 0x80104B48>
.data 0x00000004
.data 0x4182000C
.data <VERS 0x8010771C 0x8010771C 0x80107478>
.data 0x00000004
.data 0x4800000C
.data <VERS 0x80107730 0x80107730 0x8010748C>
.data 0x00000004
.data 0x7C030378
.data <VERS 0x8010BC14 0x8010BC14 0x8010B970>
.data 0x00000004
.data <VERS 0x4BEFF488 0x4BEFF488 0x4BEFF72C>
.data <VERS 0x8010E03C 0x8010E03C 0x8010DD98>
.data 0x00000004
.data <VERS 0x4BEFD078 0x4BEFD078 0x4BEFD31C>
.data <VERS 0x80112908 0x80112908 0x80112664>
.data 0x00000004
.data <VERS 0x4BEF9F98 0x4BEF9F98 0x4BEFA23C>
.data <VERS 0x8011461C 0x8011461C 0x80114378>
.data 0x00000004
.data 0x38000012
.data <VERS 0x80118854 0x80118854 0x801185B0>
.data 0x00000004
.data 0x88040016
.data <VERS 0x80118860 0x80118860 0x801185BC>
.data 0x00000004
.data 0x88040017
.data <VERS 0x80118F84 0x80118F84 0x80118CE0>
.data 0x00000004
.data <VERS 0x4BEF36BC 0x4BEF36BC 0x4BEF3960>
.data <VERS 0x8011CD34 0x8011CD34 0x8011CA90>
.data 0x0000000C
.data 0x7C030378
.data 0x3863FFFF
.data 0x4BFFFFE8
.data <VERS 0x8011CDF0 0x8011CDF0 0x8011CB4C>
.data 0x0000000C
.data 0x7C030378
.data 0x3863FFFF
.data 0x4BFFFFE8
.data <VERS 0x8011CE40 0x8011CE40 0x8011CB9C>
.data 0x0000000C
.data 0x7C040378
.data 0x3884FFFF
.data 0x4BFFFFE8
.data <VERS 0x801666E0 0x801666E0 0x80166324>
.data 0x00000008
.data 0x3C604005
.data 0x4800009C
.data <VERS 0x8016677C 0x8016677C 0x801663C0>
.data 0x00000004
.data 0x4800001C
.data <VERS 0x80171010 0x80171010 0x80170C54>
.data 0x00000004
.data <VERS 0x4BE9ABC0 0x4BE9ABC0 0x4BE9AF7C>
.data <VERS 0x80171030 0x80171030 0x80170C74>
.data 0x00000004
.data 0x60800420
.data <VERS 0x80184250 0x80184250 0x80172188>
.data 0x00000004
.data <VERS 0x4BE87378 0x4BE87378 0x4BE9A558>
.data <VERS 0x80184290 0x80184290 0x80183E94>
.data 0x00000004
.data <VERS 0x60000000 0x60000000 0x4BE87734>
.data <VERS 0x80189E20 0x80189E20 0x80183ED4>
.data 0x00000004
.data 0x60000000
.data <VERS 0x801937A8 0x801937A8 0x80189A54>
.data 0x00000004
.data 0x60000000
.data <VERS 0x801B9BA0 0x801B9BA0 0x801933DC>
.data 0x00000004
.data <VERS 0x4BE52868 0x4BE52868 0x60000000>
.data <VERS 0x801B9E74 0x801B9E74 0x801B97B4>
.data 0x00000004
.data <VERS 0x4BE51214 0x4BE51214 0x4BE52C54>
.data <VERS 0x801C62C0 0x801C62C0 0x801B9A88>
.data 0x00000004
.data <VERS 0x389F02FC 0x389F02FC 0x4BE51600>
.data <VERS 0x801CA610 0x801CA610 0x801C5EA4>
.data 0x00000004
.data <VERS 0x48000010 0x48000010 0x389F02FC>
.data <VERS 0x8021D91C 0x8021D91C 0x801CA1F4>
.data 0x00000004
.data <VERS 0x4BDEEDB4 0x4BDEEDB4 0x48000010>
.data <VERS 0x80220DDC 0x80220DDC 0x8021D098>
.data 0x00000004
.data <VERS 0x4BDEB904 0x4BDEB904 0x4BDEF638>
.data <VERS 0x80229C10 0x80229C10 0x80229354>
.data 0x00000004
.data 0x2C000001
.data <VERS 0x8022A410 0x8022A410 0x80229B54>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x8022A440 0x8022A440 0x80229B84>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x8022A470 0x8022A470 0x80229BB4>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x8022D10C 0x8022D10C 0x8022C850>
.data 0x00000004
.data 0x60000000
.data <VERS 0x8022D840 0x8022D840 0x8022CF84>
.data 0x00000004
.data 0x41810630
.data <VERS 0x8022DB34 0x8022DB34 0x8022D278>
.data 0x00000004
.data 0x4181033C
.data <VERS 0x8022DC28 0x8022DC28 0x8022D36C>
.data 0x00000004
.data 0x41810248
.data <VERS 0x8022EB64 0x8022EB64 0x8022E2A8>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x8022EB94 0x8022EB94 0x8022E2D8>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x8022EBC4 0x8022EBC4 0x8022E308>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x8022F370 0x8022F370 0x8022EAB4>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x8022F3A0 0x8022F3A0 0x8022EAE4>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x8022F3D0 0x8022F3D0 0x8022EB14>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80230974 0x80230974 0x802300B8>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x802309A4 0x802309A4 0x802300E8>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x802309D4 0x802309D4 0x80230118>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x802316E4 0x802316E4 0x80230E08>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80231714 0x80231714 0x80230E38>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80231744 0x80231744 0x80230E68>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80231FD8 0x80231FD8 0x802316FC>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80232010 0x80232010 0x80231734>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80232048 0x80232048 0x8023176C>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80234084 0x80234084 0x802337A8>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x802340B4 0x802340B4 0x802337D8>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x802340E4 0x802340E4 0x80233808>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x802366B0 0x802366B0 0x80235DD4>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x802366EC 0x802366EC 0x80235E10>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80236728 0x80236728 0x80235E4C>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80236E88 0x80236E88 0x802365AC>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80236EB8 0x80236EB8 0x802365DC>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80236EE8 0x80236EE8 0x8023660C>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x8023789C 0x8023789C 0x80236FC0>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x802378CC 0x802378CC 0x80236FF0>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x802378FC 0x802378FC 0x80237020>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80238274 0x80238274 0x80237998>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x802382A4 0x802382A4 0x802379C8>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x802382D4 0x802382D4 0x802379F8>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x8023BBA4 0x8023BBA4 0x8023B2C8>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x8023BBD4 0x8023BBD4 0x8023B2F8>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x8023BC04 0x8023BC04 0x8023B328>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80250AEC 0x80250AEC 0x80250264>
.data 0x00000004
.data 0x60000000
.data <VERS 0x80268788 0x80268788 0x80267DDC>
.data 0x00000004
.data 0x60000000
.data <VERS 0x8026E2D4 0x8026E2D4 0x8026DA74>
.data 0x00000004
.data 0x3884AAFA
.data <VERS 0x8026E3E8 0x8026E3E8 0x8026DB88>
.data 0x00000004
.data 0x3863AAFA
.data <VERS 0x8026E470 0x8026E470 0x8026DC10>
.data 0x00000004
.data 0x3883AAFA
.data <VERS 0x802BBEF4 0x802BBF38 0x802BB4B0>
.data 0x00000004
.data <VERS 0x4BD51A8C 0x4BD51A48 0x4BD524D0>
.data <VERS 0x802FC2F4 0x802FC338 0x802FB99C>
.data 0x00000004
.data 0x2C030001
.data <VERS 0x80301F58 0x80301F9C 0x80301600>
.data 0x0000001C
.data 0x48000020
.data 0x3863A830
.data <VERS 0x800DB9A4 0x800DB9A4 0x800DB98C>
.data 0x2C000023
.data 0x40820008
.data 0x3863FB28
.data 0x4800008C
.data <VERS 0x80301FF8 0x8030203C 0x803016A0>
.data 0x00000004
.data 0x4BFFFF64
.data <VERS 0x80335A50 0x80335A94 0x80335060>
.data 0x00000004
.data <VERS 0x4BCD7F50 0x4BCD7F0C 0x4BCD8940>
.data <VERS 0x80356814 0x80356858 0x80355960>
.data 0x00000004
.data 0x388001E8
.data <VERS 0x80356838 0x8035687C 0x80355984>
.data 0x00000004
.data <VERS 0x4BCB79A9 0x4BCB7965 0x4BCB885D>
.data <VERS 0x803568A8 0x803568EC 0x803559F4>
.data 0x00000004
.data 0x388001E8
.data <VERS 0x803568B8 0x803568FC 0x80355A04>
.data 0x00000004
.data <VERS 0x4BCB7929 0x4BCB78E5 0x4BCB87DD>
.data <VERS 0x804B3EF0 0x804B43D0 0x804B3738>
.data 0x00000008
.data 0x70808080
.data 0x60707070
.data <VERS 0x804C76B4 0x804C7B94 0x804C6EE4>
.data 0x00000004
.data 0x0000001E
.data <VERS 0x804C770C 0x804C7BEC 0x804C6F3C>
.data 0x00000004
.data 0x00000028
.data <VERS 0x804C7738 0x804C7C18 0x804C6F68>
.data 0x00000004
.data 0x00000032
.data <VERS 0x804C7764 0x804C7C44 0x804C6F94>
.data 0x00000004
.data 0x0000003C
.data <VERS 0x804C7774 0x804C7C54 0x804C6FA4>
.data 0x00000004
.data 0x0018003C
.data <VERS 0x804C79CC 0x804C7EAC 0x804C71FC>
.data 0x00000004
.data 0x00000028
.data <VERS 0x804CC310 0x804CC7F0 0x804CBB40>
.data 0x00000004
.data 0xFF0074EE
.data <VERS 0x805CA274 0x805D1294 0x805C996C>
.data 0x00000004
.data 0x435C0000
.data <VERS 0x805CBF10 0x805D2F30 0x805CB608>
.data 0x00000004
.data 0x46AFC800
.data <VERS 0x805CC1B0 0x805D31D0 0x805CB8A8>
.data 0x00000004
.data 0x43480000
# Belra arm bug fix (this part by fuzziqersoftware)
.data <VERS 0x800959B0 0x800959B0 0x80095724>
.data 0x00000004
.address <VERS 0x800959B0 0x800959B0 0x80095724>
bl belra_bugfix_hook1
.data <VERS 0x800959C0 0x800959C0 0x80095734>
.data 0x00000004
.address <VERS 0x800959C0 0x800959C0 0x80095734>
bl belra_bugfix_hook2
.data 0x8000B06C
.deltaof belra_bugfix_hook1, belra_bugfix_end
.address 0x8000B06C
belra_bugfix_hook1:
li r0, 1
stw [r13 - <VERS 0x2E30 0x2E30 0x2E48>], r0 # Anchor: 80039388 @ 3OE1
b [<VERS 803D4410 803D4468 803D3140>]
belra_bugfix_hook2:
li r4, 0
stw [r13 - <VERS 0x2E30 0x2E30 0x2E48>], r4
lwz r4, [r28 + 0x04]
blr
belra_bugfix_end:
.data 0x00000000
.data 0x00000000
@@ -0,0 +1,554 @@
.meta name="Bug fixes"
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
# Original code by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
.versions 3OE2 3OJ3 3OJ4 3OJ5 3OP0
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
.data 0x8000B088
.data 0x00000058
.data 0x7FA3EB78
.data 0x38800000
.data <VERS 0x481AECC1 0x481AEB91 0x481B1C09 0x481AEC5D 0x481AF17D>
.data 0x7FA3EB78
.data <VERS 0x481AEF90 0x481AEE60 0x481B1ED8 0x481AEF2C 0x481AF44C>
.data 0x881F0000
.data 0x28090001
.data 0x4082000C
.data 0x881F0001
.data 0x3BFF0002
.data <VERS 0x48100A54 0x48100AC4 0x48100B58 0x48100A44 0x48100C44>
.data 0x39200000
.data <VERS 0x481009E5 0x48100A55 0x48100AE9 0x481009D5 0x48100BD5>
.data 0x7F43D378
.data 0x7F64DB78
.data 0x7F85E378
.data 0x7FA6EB78
.data 0x7FC7F378
.data 0x7FE8FB78
.data 0x39200001
.data <VERS 0x481009C5 0x48100A35 0x48100AC9 0x481009B5 0x48100BB5>
.data <VERS 0x48102E5C 0x48102EC0 0x4810300C 0x48102E4C 0x48103040>
.data 0x8000B5C8
.data 0x00000014
.data 0x80630098
.data <VERS 0x483D90F1 0x483D70D1 0x483D8F71 0x483D8D21 0x483D7BE1>
.data 0x807F042C
.data 0x809F0430
.data <VERS 0x48178DB0 0x48178C88 0x48178DEC 0x48178D4C 0x48179274>
.data 0x8000BBD0
.data 0x00000020
.data 0x809F0370
.data 0x3884FC00
.data 0x909F0370
.data 0x807F0014
.data 0x28030000
.data 0x41820008
.data 0x90830060
.data <VERS 0x48165548 0x48165420 0x48165678 0x481654E4 0x48165A0C>
.data 0x8000C3F8
.data 0x0000007C
.data 0x28040000
.data 0x4D820020
.data 0x9421FFF0
.data <VERS 0x481AD950 0x481AD820 0x481B0898 0x481AD8EC 0x481ADE0C>
.data 0x9421FFE0
.data 0x7C0802A6
.data 0x90010024
.data 0xBF410008
.data 0x7C7F1B78
.data 0x4BFFFFDD
.data 0x3BC00000
.data 0x3BBF0D04
.data 0x837F032C
.data 0x839D0000
.data 0x7F83E379
.data 0x41820018
.data 0x38800001
.data <VERS 0x480FEC6D 0x480FECDD 0x480FEDC9 0x480FEC5D 0x480FEE5D>
.data 0x7F83E378
.data 0x38800001
.data <VERS 0x480FEDDD 0x480FEE4D 0x480FEF49 0x480FEDCD 0x480FEFCD>
.data 0x3BBD0004
.data 0x3BDE0001
.data 0x2C1E000D
.data 0x4180FFD4
.data 0x937F032C
.data 0xBB410008
.data 0x80010024
.data 0x7C0803A6
.data 0x38210020
.data 0x4E800020
.data 0x8000C640
.data 0x00000014
.data 0x54800673
.data 0x41820008
.data 0x38800000
.data 0x38040009
.data <VERS 0x4810C858 0x4810C8B0 0x4810C98C 0x4810C848 0x4810CA30>
.data 0x8000C6D0
.data 0x00000020
.data 0x38000001
.data 0x901D0054
.data 0x807D0024
.data <VERS 0x482122F8 0x48211324 0x48212210 0x48211FC4 0x48211B90>
.data 0x38000001
.data 0x901F0378
.data 0x807F0024
.data <VERS 0x482157A8 0x482147D4 0x482156C0 0x48215474 0x48215040>
.data 0x8000C8A0
.data 0x00000014
.data 0x1C00000A
.data 0x57E407BD
.data 0x41820008
.data 0x7FA00734
.data <VERS 0x48105F54 0x48105FB8 0x48106190 0x48105F44 0x48106138>
.data 0x8000C8C0
.data 0x00000010
.data 0x7000000F
.data 0x7000004F
.data 0x2C000004
.data 0x4E800020
.data 0x8000D980
.data 0x00000014
.data 0x807C0000
.data 0x2C030013
.data 0x40820008
.data 0x38600002
.data <VERS 0x482AFAE8 0x482AEA54 0x482AFB9C 0x482AF934 0x482AF27C>
.data 0x8000D9A0
.data 0x00000018
.data <VERS 0xC042FC88 0xC042FC80 0xC042FC80 0xC042FC80 0xC042FC88>
.data 0x807E0030
.data 0x70630020
.data 0x41820008
.data <VERS 0xC042FCA0 0xC042FC98 0xC042FC98 0xC042FC98 0xC042FCA0>
.data <VERS 0x48329BC0 0x4832871C 0x48329C38 0x483299EC 0x48329004>
.data 0x8000E1E0
.data 0x0000001C
.data 0x7FC802A6
.data 0x38A00000
.data 0x38C0001E
.data 0x38E00040
.data <VERS 0x480786D5 0x4807859D 0x48078715 0x480786C5 0x4807869D>
.data 0x7FC803A6
.data 0x4E800020
.data <VERS 0x8001304C 0x8001309C 0x80013364 0x8001304C 0x800130C4>
.data 0x00000004
.data 0x4BFFFCC0
.data <VERS 0x800142BC 0x8001430C 0x800146A4 0x800142BC 0x80014334>
.data 0x00000004
.data <VERS 0x4BFF8605 0x4BFF85B5 0x4BFF821D 0x4BFF8605 0x4BFF858D>
.data <VERS 0x80015CE4 0x80015D34 0x80016174 0x80015CE4 0x80015D5C>
.data 0x00000004
.data <VERS 0x4BFF6BE1 0x4BFF6B91 0x4BFF6751 0x4BFF6BE1 0x4BFF6B69>
.data <VERS 0x8009194C 0x80091814 0x8009198C 0x8009193C 0x80091914>
.data 0x00000008
.data 0x4800024D
.data 0xB3C3032C
.data <VERS 0x800BCB90 0x800BCA58 0x800BCBD0 0x800BCB80 0x800BCB58>
.data 0x00000004
.data 0x48000010
.data <VERS 0x80104CB4 0x80104D24 0x80104DE0 0x80104CA4 0x80104EA4>
.data 0x00000004
.data 0x4182000C
.data <VERS 0x801075E4 0x80107654 0x80107708 0x801075D4 0x801077D4>
.data 0x00000004
.data 0x4800000C
.data <VERS 0x801075F8 0x80107668 0x8010771C 0x801075E8 0x801077E8>
.data 0x00000004
.data 0x7C030378
.data <VERS 0x8010BB00 0x8010BB70 0x8010BC04 0x8010BAF0 0x8010BCF0>
.data 0x00000004
.data <VERS 0x4BEFF59C 0x4BEFF52C 0x4BEFF498 0x4BEFF5AC 0x4BEFF3AC>
.data <VERS 0x8010DF34 0x8010DF98 0x8010E0E4 0x8010DF24 0x8010E118>
.data 0x00000004
.data <VERS 0x4BEFD180 0x4BEFD11C 0x4BEFCFD0 0x4BEFD190 0x4BEFCF9C>
.data <VERS 0x80112800 0x80112864 0x80112A3C 0x801127F0 0x801129E4>
.data 0x00000004
.data <VERS 0x4BEFA0A0 0x4BEFA03C 0x4BEF9E64 0x4BEFA0B0 0x4BEF9EBC>
.data <VERS 0x80114534 0x8011458C 0x80114634 0x80114524 0x8011470C>
.data 0x00000004
.data 0x38000012
.data <VERS 0x80118774 0x801187CC 0x8011885C 0x80118764 0x8011894C>
.data 0x00000004
.data 0x88040016
.data <VERS 0x80118780 0x801187D8 0x80118868 0x80118770 0x80118958>
.data 0x00000004
.data 0x88040017
.data <VERS 0x80118EA4 0x80118EFC 0x80118FD8 0x80118E94 0x8011907C>
.data 0x00000004
.data <VERS 0x4BEF379C 0x4BEF3744 0x4BEF3668 0x4BEF37AC 0x4BEF35C4>
.data <VERS 0x8011CC7C 0x8011CCD4 0x8011CD0C 0x8011CC6C 0x8011CE54>
.data 0x0000000C
.data 0x7C030378
.data 0x3863FFFF
.data 0x4BFFFFE8
.data <VERS 0x8011CD38 0x8011CD90 0x8011CDC8 0x8011CD28 0x8011CF10>
.data 0x0000000C
.data 0x7C030378
.data 0x3863FFFF
.data 0x4BFFFFE8
.data <VERS 0x8011CD88 0x8011CDE0 0x8011CE18 0x8011CD78 0x8011CF60>
.data 0x0000000C
.data 0x7C040378
.data 0x3884FFFF
.data 0x4BFFFFE8
.data <VERS 0x80166800 0x801666D8 0x80166848 0x8016679C 0x80166CC4>
.data 0x00000008
.data 0x3C604005
.data 0x4800009C
.data <VERS 0x8016689C 0x80166774 0x801668E4 0x80166838 0x80166D60>
.data 0x00000004
.data 0x4800001C
.data <VERS 0x80171130 0x80171008 0x80171260 0x801710CC 0x801715F4>
.data 0x00000004
.data <VERS 0x4BE9AAA0 0x4BE9ABC8 0x4BE9A970 0x4BE9AB04 0x4BE9A5DC>
.data <VERS 0x80171150 0x80171028 0x80171280 0x801710EC 0x80171614>
.data 0x00000004
.data 0x60800420
.data <VERS 0x80184384 0x8018425C 0x801843C0 0x80184320 0x80184848>
.data 0x00000004
.data <VERS 0x4BE87244 0x4BE8736C 0x4BE87208 0x4BE872A8 0x4BE86D80>
.data <VERS 0x801843C4 0x8018429C 0x80184400 0x80184360 0x80184888>
.data 0x00000004
.data 0x60000000
.data <VERS 0x80189F54 0x80189E2C 0x80189F90 0x80189EF0 0x8018A418>
.data 0x00000004
.data 0x60000000
.data <VERS 0x801938D8 0x801937B0 0x80193914 0x80193874 0x80193D9C>
.data 0x00000004
.data 0x60000000
.data <VERS 0x801B9D50 0x801B9C20 0x801BCC98 0x801B9CEC 0x801BA20C>
.data 0x00000004
.data <VERS 0x4BE526B8 0x4BE527E8 0x4BE4F770 0x4BE5271C 0x4BE521FC>
.data <VERS 0x801BA024 0x801B9EF4 0x801BCF6C 0x801B9FC0 0x801BA4E0>
.data 0x00000004
.data <VERS 0x4BE51064 0x4BE51194 0x4BE4E11C 0x4BE510C8 0x4BE50BA8>
.data <VERS 0x801C6490 0x801C6360 0x801C6604 0x801C642C 0x801C694C>
.data 0x00000004
.data 0x389F02FC
.data <VERS 0x801CA810 0x801CA6E0 0x801CB5EC 0x801CA7AC 0x801CACCC>
.data 0x00000004
.data 0x48000010
.data <VERS 0x8021E9D0 0x8021D9FC 0x8021E8E8 0x8021E69C 0x8021E268>
.data 0x00000004
.data <VERS 0x4BDEDD00 0x4BDEECD4 0x4BDEDDE8 0x4BDEE034 0x4BDEE468>
.data <VERS 0x80221E90 0x80220EBC 0x80221DA8 0x80221B5C 0x80221728>
.data 0x00000004
.data <VERS 0x4BDEA850 0x4BDEB824 0x4BDEA938 0x4BDEAB84 0x4BDEAFB8>
.data <VERS 0x8022ACC4 0x80229CF0 0x8022ABDC 0x8022A990 0x8022A55C>
.data 0x00000004
.data 0x2C000001
.data <VERS 0x8022B4C4 0x8022A4F0 0x8022B3E0 0x8022B190 0x8022AD5C>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x8022B4F4 0x8022A520 0x8022B410 0x8022B1C0 0x8022AD8C>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x8022B524 0x8022A550 0x8022B440 0x8022B1F0 0x8022ADBC>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x8022E1C0 0x8022D1EC 0x8022E128 0x8022DE8C 0x8022DA58>
.data 0x00000004
.data 0x60000000
.data <VERS 0x8022E8F4 0x8022D920 0x8022E85C 0x8022E5C0 0x8022E18C>
.data 0x00000004
.data 0x41810630
.data <VERS 0x8022FC18 0x8022EC44 0x8022FB30 0x8022F8E4 0x8022F4B0>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x8022FC48 0x8022EC74 0x8022FB60 0x8022F914 0x8022F4E0>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x8022FC78 0x8022ECA4 0x8022FB90 0x8022F944 0x8022F510>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80230424 0x8022F450 0x80230340 0x802300F0 0x8022FCBC>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80230454 0x8022F480 0x80230370 0x80230120 0x8022FCEC>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80230484 0x8022F4B0 0x802303A0 0x80230150 0x8022FD1C>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80231A28 0x80230A54 0x80231940 0x802316F4 0x802312C0>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80231A58 0x80230A84 0x80231970 0x80231724 0x802312F0>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80231A88 0x80230AB4 0x802319A0 0x80231754 0x80231320>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80232798 0x802317C4 0x802326B0 0x80232464 0x80232030>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x802327C8 0x802317F4 0x802326E0 0x80232494 0x80232060>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x802327F8 0x80231824 0x80232710 0x802324C4 0x80232090>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x8023308C 0x802320B8 0x80232FA4 0x80232D58 0x80232924>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x802330C4 0x802320F0 0x80232FDC 0x80232D90 0x8023295C>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x802330FC 0x80232128 0x80233014 0x80232DC8 0x80232994>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80235138 0x80234164 0x80235050 0x80234E04 0x802349D0>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80235168 0x80234194 0x80235080 0x80234E34 0x80234A00>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80235198 0x802341C4 0x802350B0 0x80234E64 0x80234A30>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80237764 0x80236790 0x8023767C 0x80237430 0x80236FFC>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x802377A0 0x802367CC 0x802376B8 0x8023746C 0x80237038>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x802377DC 0x80236808 0x802376F4 0x802374A8 0x80237074>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80237F3C 0x80236F68 0x80237E54 0x80237C08 0x802377D4>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80237F6C 0x80236F98 0x80237E84 0x80237C38 0x80237804>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80237F9C 0x80236FC8 0x80237EB4 0x80237C68 0x80237834>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80238950 0x8023797C 0x80238868 0x8023861C 0x802381E8>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80238980 0x802379AC 0x80238898 0x8023864C 0x80238218>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x802389B0 0x802379DC 0x802388C8 0x8023867C 0x80238248>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80239328 0x80238354 0x80239240 0x80238FF4 0x80238BC0>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x80239358 0x80238384 0x80239270 0x80239024 0x80238BF0>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x80239388 0x802383B4 0x802392A0 0x80239054 0x80238C20>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x8023CC58 0x8023BC84 0x8023CB70 0x8023C924 0x8023C4F0>
.data 0x00000004
.data 0x3880FF00
.data <VERS 0x8023CC88 0x8023BCB4 0x8023CBA0 0x8023C954 0x8023C520>
.data 0x00000004
.data 0x3880FE80
.data <VERS 0x8023CCB8 0x8023BCE4 0x8023CBD0 0x8023C984 0x8023C550>
.data 0x00000004
.data 0x3880FDB0
.data <VERS 0x80251C68 0x80250CB0 0x80251CA4 0x802519A4 0x802514B0>
.data 0x00000004
.data 0x60000000
.data <VERS 0x80269B5C 0x80268A88 0x80269AE4 0x80269898 0x802693A4>
.data 0x00000004
.data 0x60000000
.data <VERS 0x8026F6FC 0x8026E738 0x8026F794 0x8026F548 0x8026EF44>
.data 0x00000004
.data 0x3884AAFA
.data <VERS 0x8026F810 0x8026E84C 0x8026F8A8 0x8026F65C 0x8026F058>
.data 0x00000004
.data 0x3863AAFA
.data <VERS 0x8026F898 0x8026E8D4 0x8026F930 0x8026F6E4 0x8026F0E0>
.data 0x00000004
.data 0x3883AAFA
.data <VERS 0x802BD474 0x802BC3E0 0x802BD528 0x802BD2C0 0x802BCC08>
.data 0x00000004
.data <VERS 0x4BD5050C 0x4BD515A0 0x4BD50458 0x4BD506C0 0x4BD50D78>
.data <VERS 0x802FDD28 0x802FC968 0x802FDE60 0x802FDB6C 0x802FD100>
.data 0x00000004
.data 0x2C030001
.data <VERS 0x8030398C 0x803025CC 0x80303A1C 0x803037D0 0x80302D64>
.data 0x0000001C
.data 0x48000020
.data 0x3863A830
.data <VERS 0x800DB9C4 0x800DB994 0x800DB9B4 0x800DB9B4 0x800DBA04>
.data 0x2C000023
.data 0x40820008
.data 0x3863FB28
.data 0x4800008C
.data <VERS 0x80303A2C 0x8030266C 0x80303ABC 0x80303870 0x80302E04>
.data 0x00000004
.data 0x4BFFFF64
.data <VERS 0x80337570 0x803360CC 0x803375E8 0x8033739C 0x803369B4>
.data 0x00000004
.data <VERS 0x4BCD6430 0x4BCD78D4 0x4BCD63B8 0x4BCD6604 0x4BCD6FEC>
.data <VERS 0x80358440 0x80356D64 0x803582C0 0x80358074 0x80357834>
.data 0x00000004
.data 0x388001E8
.data <VERS 0x80358464 0x80356D88 0x803582E4 0x80358098 0x80357858>
.data 0x00000004
.data <VERS 0x4BCB5D7D 0x4BCB7459 0x4BCB5EFD 0x4BCB6149 0x4BCB6989>
.data <VERS 0x803584D4 0x80356DF8 0x80358354 0x80358108 0x803578C8>
.data 0x00000004
.data 0x388001E8
.data <VERS 0x803584E4 0x80356E08 0x80358364 0x80358118 0x803578D8>
.data 0x00000004
.data <VERS 0x4BCB5CFD 0x4BCB73D9 0x4BCB5E7D 0x4BCB60C9 0x4BCB6909>
.data <VERS 0x804B8990 0x804B6E58 0x804B92F8 0x804B90B8 0x804B8E10>
.data 0x00000008
.data 0x70808080
.data 0x60707070
.data <VERS 0x804CC1E4 0x804CA61C 0x804CCB6C 0x804CC90C 0x804CC5D4>
.data 0x00000004
.data 0x0000001E
.data <VERS 0x804CC23C 0x804CA674 0x804CCBC4 0x804CC964 0x804CC62C>
.data 0x00000004
.data 0x00000028
.data <VERS 0x804CC268 0x804CA6A0 0x804CCBF0 0x804CC990 0x804CC658>
.data 0x00000004
.data 0x00000032
.data <VERS 0x804CC294 0x804CA6CC 0x804CCC1C 0x804CC9BC 0x804CC684>
.data 0x00000004
.data 0x0000003C
.data <VERS 0x804CC2A4 0x804CA6DC 0x804CCC2C 0x804CC9CC 0x804CC694>
.data 0x00000004
.data 0x0018003C
.data <VERS 0x804CC4FC 0x804CA934 0x804CCE84 0x804CCC24 0x804CC8EC>
.data 0x00000004
.data 0x00000028
.data <VERS 0x804D0E58 0x804CF290 0x804D17E0 0x804D1580 0x804D1248>
.data 0x00000004
.data 0xFF0074EE
.data <VERS 0x805DAAB4 0x805D3F6C 0x805DB40C 0x805DB1AC 0x805D6CF4>
.data 0x00000004
.data 0x435C0000
.data <VERS 0x805DC750 0x805D5C08 0x805DD0A8 0x805DCE48 0x805D8990>
.data 0x00000004
.data 0x46AFC800
.data <VERS 0x805DC9F0 0x805D5EA8 0x805DD348 0x805DD0E8 0x805D8C30>
.data 0x00000004
.data 0x43480000
.data 0x00000000
.data 0x00000000
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerGC
.data 0x805C5650
.data 0x801E3F9C
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerGC
.data 0x805CC630
.data 0x801E3F9C
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerGC
.data 0x805D5E50
.data 0x801E405C
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerGC
.data 0x805C4D58
.data 0x801E3B38
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerGC
.data 0x805CF320
.data 0x801E40BC
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerGC
.data 0x805D67A0
.data 0x801E4290
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerGC
.data 0x805D6540
.data 0x801E4008
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerGC
.data 0x805D2090
.data 0x801E4698
size:
.data 0x00000000
data:
@@ -1,3 +1,13 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
entry_ptr:
reloc0:
.offsetof start
start:
stwu [r1 - 0x10], r1
mflr r0
stw [r1 + 0x14], r0
@@ -30,3 +40,9 @@ resume:
get_data_addr:
bl resume
.data <VERS 0x805C4D58 0x805CF320 0x805D67A0 0x805D6540 0x805C5650 0x805CC630 0x805D5E50 0x805D2090>
.data <VERS 0x801E3B38 0x801E40BC 0x801E4290 0x801E4008 0x801E3F9C 0x801E3F9C 0x801E405C 0x801E4698>
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerXB
.data 0x00723F68
.data 0x002DDB00
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerXB
.data 0x007237E8 # should_allow_protected_commands
.data 0x002DE000 # handle_6x(void* data @ ecx, uint32_t size @ eax)
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerXB
.data 0x0071E8C8
.data 0x002DBBA0
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerXB
.data 0x0071EF28
.data 0x002DC720
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerXB
.data 0x00726A68
.data 0x002DDFE0
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerXB
.data 0x00723F68
.data 0x002DDB30
size:
.data 0x00000000
data:
@@ -1,14 +0,0 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
entry_ptr:
reloc0:
.offsetof start
start:
.include CallProtectedHandlerXB
.data 0x007242E8
.data 0x002DE030
size:
.data 0x00000000
data:
@@ -0,0 +1,36 @@
.meta hide_from_patches_menu
.meta name="CallProtectedHandler"
.meta description=""
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
entry_ptr:
reloc0:
.offsetof start
start:
jmp get_data_addr
resume:
xchg ebx, [esp]
mov edx, [ebx]
mov dword [edx], 1
mov edx, [ebx + 4]
lea ecx, [ebx + 0x0C]
mov eax, [ebx + 8]
call edx
mov edx, [ebx]
mov dword [edx], 0
pop ebx
ret
get_data_addr:
call resume
.data <VERS 0x0071E8C8 0x0071EF28 0x00726A68 0x00723F68 0x007237E8 0x00723F68 0x007242E8>
.data <VERS 0x002DBBA0 0x002DC720 0x002DDFE0 0x002DDB00 0x002DE000 0x002DDB30 0x002DE030>
size:
.data 0x00000000
data:
@@ -1,20 +0,0 @@
jmp get_data_addr
resume:
xchg ebx, [esp]
mov edx, [ebx]
mov dword [edx], 1
mov edx, [ebx + 4]
lea ecx, [ebx + 0x0C]
mov eax, [ebx + 8]
call edx
mov edx, [ebx]
mov dword [edx], 0
pop ebx
ret
get_data_addr:
call resume
@@ -1,47 +0,0 @@
.meta name="Chat"
.meta description="Enables extended\nWord Select and\nstops the Log\nWindow from\nscrolling with L+R"
# Original codes by Ralf @ GC-Forever and Aleron Ives
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksGC
.data 0x8034525C # Extended Word Select Menu (PSO PCv2 Style)
.data 0x00000004
.address 0x8034525C
li r3, 0
.data 0x80268788 # Chat Log Window LF/TAB Bug Fix
.data 0x00000004
.address 0x80268788
nop
.data 0x80250AEC # Chat Bubble Window TAB Bug Fix
.data 0x00000004
.address 0x80250AEC
nop
.data 0x8000D6A0 # Chat Log Window: Scroll Lock (Hold L+R)
.deltaof scroll_lock_hook, scroll_lock_hook_end
.address 0x8000D6A0
scroll_lock_hook:
lis r3, 0x8051
lhz r3, [r3 - 0x6C50]
andi. r0, r3, 0x0003
cmplwi r0, 3
beqlr
stfs [r28 + 0x0084], f1
blr
scroll_lock_hook_end:
.data 0x80268874 # Chat Log Window: Scroll Lock (Hold L+R)
.data 0x00000004
.address 0x80268874
bl scroll_lock_hook
.data 0x00000000
.data 0x00000000

Some files were not shown because too many files have changed in this diff Show More