rainwarrior wrote:
DRW wrote:
I assume a TAS speedrunner knows the game well enough to know when he can make inputs.
Well, they certainly do when they have something that can indicate it for them, like maybe this "lag" counter.
And how many times would a speedrunner actually need this? The
only time where the lag counter indicates the possibility of inputs and not actual slowdowns would be during some status screens
and only if the game is programmed in a way so that the input isn't read during this time.
But the lag counter as an input indicator helps you in no way for, well, basically evey situation imaginable:
If you want to know when you can attack again after you already attacked, the lag counter will not help you. If you want to know when you can move again after landing on the ground or after being hit, the lag counter will not help you.
Using the lag counter as an input indicator helps only in one way: If the level starts with a status screen. And even in this case it's pretty much useless: Firstly, not every game is programmed so that status screens increase the lag counter constantly. Secondly, the moment when input is possible is usually as soon as the screen shows the level again.
So, yeah, the lag counter isn't mis-labeled. It's not intended as an indicator to know whether you can input commands. It is what it says it is: A lag counter. To check whenever the game requires more than one screen to render a scene. To see whether the game experienced actual slowdown. Not an indicator to tell the speedrunner: "Now your button press has an effect and now it doesn't". Which would be a situation that couldn't be implemented with a lag counter in 99.999% of every game situation anyway.
rainwarrior wrote:
If you have more than one loop for different modes, there is really no point to reading the input and ignoring it. Extra code for nothing.
Who said anything about extra code, even if there are more statuses for the game? And who said that I have more than one loop to begin with?
Code:
StartGameLoop:
ReadInput
if Status = TextScreen
ProcessTextScreen
else
ProcessLevel
WaitForNmi
goto StartGameLoop
If you seriously have several game loops like in:
Code:
if Status = TextScreenWithInput
StartTextScreenWithInput:
ReadInput
ProcessTextScreenWithInput
WaitForNmi
goto StartTextScreenWithInput
else if Status = AutomaticTextScreen
StartAutomaticTextScreen:
; No input reading
ProcessAutomaticTextScreen
WaitForNmi
goto StartAutomaticTextScreen
else
StartLevel:
ReadInput
ProcessLevel
WaitForNmi
goto StartLevel
maybe
you should think about removing redundant code.
I on the other hand cannot think of any reason why you should
ever have more than one game loop.
It's one game loop to do all the generic stuff at the start (read input) and the end (update music values, wait for nmi). And one if-else (or switch case 1, case 2, case 3 etc.) to distinguish between the different game sections that require completely different logic, like title screen, level, in-game menu etc.
But in no way would I ever use more than one
game loop. Why should anybody do that?
rainwarrior wrote:
If you're not in a loop (e.g. loading level data to the screen, filling CHR-RAM, etc.) then there's really no place to read the input anyway, and again no point in adding extra code to do so if you're going to ignore it.
Again, where do you see extra code or anything like that?
If I load level data, then some sub function in ProcessGameplay will set PpuMaskBuffer to 0, so that NMI disables the PpuMask. Then the function will update all graphics and afterward set PpuMaskBuffer back to its original value.
None of this contradicts or requires any additional code regarding the fact that controller input is always the first thing in the game logic.
gauauu wrote:
Actually in the game I'm working on now, with how I've arranged my bank-switching, I do have different NMI handlers for different situations. Each bank has a specialized duty, so the NMI routine can be adapted to do exactly what that situation needs.
Banshaku wrote:
In my current game engine I update the NMI based on the situation so in a stage, a NMI could be changed more than once.
What do your NMIs do, so that you need different ones?
Mine does these things:
Check whether we actually want to run the NMI's code.
Set the WaitForNmi flag back to false.
Set the PpuMask buffer value to the actual PpuMask register.
Copy the sprite array to OAM.
Update the PPU based on a buffer array.
Update name table and scrolling based on buffer values.
Call the sound update function.
Every section-related things are written in the regular game logic. The NMI does nothing but those completely generic things.
Even the question if you update a text in a text screen or a destroyed bush on the playfield makes no difference once the NMI is reached. Because the buffer array only includes the data length, the PPU address where to draw to and the tiles. Then it has either a 0 or another collection of data length, PPU address and tiles.
The distinct stuff (text rendering preparation is processed differently from background element change preparation since both read their data from totally different sources, access different banks etc.) is only ever done in the regular game logic.
The narrow window of vblank that gets started by the call to NMI never wastes time to do section-specific stuff. It's completely agnostic to anything that's actually going on and merely puts values into the PPU and the APU based on some general-purpose variables.
That's why I never need more than one NMI, nor does NMI need to check for the current game section.