Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Developing Pointdevice Mode for all TH danmaku games #174

Open
ijwzac opened this issue Jul 13, 2024 · 2 comments
Open

Developing Pointdevice Mode for all TH danmaku games #174

ijwzac opened this issue Jul 13, 2024 · 2 comments

Comments

@ijwzac
Copy link

ijwzac commented Jul 13, 2024

Hi all, I am a CS student who is developing a fork of thprac that implements a Pointdevice Mode that supports all TH danmaku games (probably except th9 and th19). Some basic functionalities are already done like detecting loss of life and overwriting section in practice mode. But there are some obstacles.

Two biggest challenge: (1) Is there a function that can immediately reload the current stage? (2) How to get the current section number?
(Edit: the second is solved by Cheat Engine. For example, 4e73f0/4e73f8 is the stage/section in th15.)
Forgive my limited knowledge of reverse engineering...


Here is something I tried but doesn't work well:

  • When section or stage is changed, store it in global variables
  • After player chooses "Restart game" (the option that restarts from the first stage), invoke a modified version of THSectionPatch() (the function that warps to a section in practice mode), which sets the section and stage

What will happen:

  • If this is stage 0 in Story mode, it works fine most of the time
  • If this is not stage 0 in Story mode, the game may crash, which makes sense since "Restart game" loads the first stage while I tell the game to jump to a section in a later stage
  • It works fine in Practice mode regardless of the stage, which also makes sense because "Restart game" loads the current stage in Practice mode
  • Sometimes boss' AI can be messed up, stopping attacking player until the next section, which is a minor issue compared to previous ones

I also don't understand what are ECLJump and ECLSetChapter. I just invoke THPatch() with modified parameters, and sometimes it works sometimes it doesn't.


Any help is greatly appreciated! I hope this mode will bring joy to all of us soon.

@32th-System
Copy link
Member

First, I would recommend that you check out https://github.com/exphp-share/th-re-data. Now, to answer your questions.

Is there a function that can immediately reload the current stage?

Yes... sort of.

In Touhou there is a variable called the game mode. Well, it's three actually (the current gamemode, the next gamemode (which is the variable you actually want to modify if you want to change it), and the previous gamemode). Examples of gamemodes are:

  • 4: main menu

  • 7: in game

  • 10: reload the game. This does the same thing as choosing retry in the pause menu

  • 15: ending
    But also:

  • 14: reload the current stage

So setting the gamemode to 14 (or 0xE) does exactly what you want.

I just invoke THPatch() with modified parameters, and sometimes it works sometimes it doesn't + Sometimes boss' AI can be messed up

This is because reloading does not reload the ECL scripts. The game keeps using the scripts it had already loaded previously.

thprac also handles warping to a chapter within the stage vs warping to a boss with different functions. THStageWarp is used to warp to stage sections, not THPatch. The function THSectionPatch knows which one to call. The reason for that is that thprac didn't originally support stage section warping. As a result, the feature is very hacked on.

Of course, if you perform a reset in a stage that's not 1, the game will reload the script for stage 1. However, setting the gamemode to 14 will never reload the script.

ECLJump

This is a utility function that creates a jump instruction in the ECL script to skip over a few other instructions. This does turn the data immediately after the newly created jump into garbage, but the ECL parser will never try to run that since it will jump over that due to the jump instruction.

ECLSetChapter

Because making sure that the internal chapter number is set correctly matters a lot in th15, thprac will also do that. It wants to make sure though that it sets the chapter number at the correct time though. The code Because of that, instead of just doing it directly, it will activate a hook that will set the chapter number and then deactivate itself. The thXX_patch_main hook is at the end of GameThread::thread_start

@ijwzac
Copy link
Author

ijwzac commented Jul 14, 2024

Hi 32th-System,

Thank you so much for the detailed explanation! I have been checking out th-re-data (astonishing work!) and implementing PointDevice mode on TH15's EX stage. Still have trouble reading ECL-related instructions but the existing ones are really helpful.

By setting gamemode_next to 14 and invoking THPatch() and THWarpStage() with tweaked parameters that represents the current section of player, I am glad to say now it kind of works! I am able to play through EX stage and reset to the checkpoint when about to lose life.

However, my current implementation has some bugs:

  1. The BGM always replays, and is always the first BGM "A World of Nightmares Never Seen Before", even if I use Everlasting BGM. I think I can solve this one by myself with the help of the existing ElBgmTest() function
  2. Seems that simply invoking THPatch() with tweaked parameters doesn't work well sometimes. Reseting during any Non Spellcard will actually reset the game to the previous Spellcard, and Doremi insists to come out and cast her third Spellcard if player resets at warp section 6~9, LOL

Reset in warp section 7:
Capture

Doremi cut into section 7 where she doesn't belong to:
Capture2

About the second problem, do you think it's because the ECL script manipulation instructions in THPatch() only works for jumping to a section with Practice mode, and doesn't work for cleaning the game's current script and jumping to a section with gamemode_next = 14?

If so, it would be more tricky than I thought since I don't know how you did those fantastic job with ECL scripts. Is there a tutorial for this? (Edit: found Priw8's tutorial, but still hard to understand how thprac developers figured out those instructions) Maybe I can force player to exit to practice mode and start practice with parameters that will jump to the current section, but this would be a bad design when I develop the PointDevice mode for other TH story modes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants