The Marvelous Multi-tile!

Post Reply
User avatar
Bucket Mouse
Posts: 316
Joined: Wed Mar 07, 2018 2:25 am

The Marvelous Multi-tile!

Post by Bucket Mouse » Wed Mar 13, 2019 5:23 am

During the development of Pandora's Blocks I set out to create a new type of tile. The reason being I needed specific things to happen on specific screens. The easiest way to introduce custom code into NESMaker is through a tile, but you only get a handful of extra tiles, and wasting an entire tile (or two) just for one screen....it wasn't ideal for the kind of cutscenes I dreamed of making.

I needed a Multi-tile. You step on it, it cycles through a list of commands. "If you're on X screen, make this happen, if not, ignore this.....now if you're on Y screen, make THIS happen, if not, ignore this....now if you're on Z screen...."

The crucial thing I needed, the missing piece of the puzzle, was a way to specifically name the screens where certain things were to happen. What was the variable that stored the specific screen address when you were at it? What are specific screens CALLED? I had no idea.

After some experimentation, the variable newScreen seemed to work. This is part of what I wrote for the first few screens of action:

Code: Select all

	LDA #$03
    CMP newScreen
    BNE trainstop1
	
    ChangeObjectState #$03, #$02
	JSR autotext
	JMP dontdoanything
	
		trainstop1:
	LDA #$04
	CMP newScreen
    BNE trainstop2
	
		LDX player1_object
	DeactivateCurrentObject
	;	LDA Object_x_hi,x
	;STA temp
	;LDA Object_y_hi,x
	;STA temp1
	;CreateObject temp, temp1, #$11, #$00, currentNametable
	;padLoop:
	;	LDA gamepad
	 ;   AND #%00000010
	;	BEQ padLoop
	  ;  INC padPound
	;	LDA #$20
	;	CMP padPound
	;	BEQ autotext
	;JMP padLoop
	
		trainstop2:
	LDA #$05
	CMP newScreen
    BNE trainstop3
"Trainstop" was my way of dealing with the annoying, extremely limited amount of space you have to branch something before it goes "out of range." It has the "range" of a Radio Shack walkie-talkie from 1983.

You can see a lot of commented-out material here. Originally, when Pandora slept, she would only wake after the player pressed random NES buttons exactly twenty times. I could not figure out how to get the ASM to sense more than one button at a time so the abandoned version you see up above looked for B. But even this didn't work, and I had zero time to mess around any further, so I just faked it by putting the sleep animation on a timer. Then her sprite had to change from a horizontal sprite to a vertical one, which is impossible in NESMaker natively. So the timer had to be an invisible monster sprite traveling across the screen until it hit a special tile that would erase that sprite and put the new one in its place.

newScreen worked for a few screens, but then with no explanation it did not work for the later ones. I had to quickly add a new variable called screenNumber, add a tally per screen load, and put it in the place where newScreen was. This fix would only work for the kind of "game" I was making. If I wanted cutscenes like this in an actual game that had open-world roaming, I would have to find the magic variable that named each screen.

After Pandora's Blocks was done, I had the time again to search. The macro for "GoToScreen" provided a BIG hint:

Code: Select all

MACRO GoToScreen arg0, arg1, arg2
	; arg 0 = screen to warp to.
	; arg 1 = map
	; arg 2 = transition type
What was argument zero, usually? In almost every instance of GoToScreen, it's warpToScreen.

Code: Select all

GoToScreen warpToScreen, temp, #$02
"Temp" is either #$01 or #$02 depending on if you're in the overworld or the underworld map.

I tested out my theory by replacing warpToScreen with a specific number. I quickly built something on the twentieth screen in the grid and commanded a tile to do this from another screen:

Code: Select all

GoToScreen #$20, #$01, #$02
it went someplace completely random. I thought "maybe the screen names are in hex." But $13 didn't work either.

Fortunately I was nearly there. My next lark was to just enter a hex number with the regular number symbols in front of it. Obviously wrong and against the rules, but it....worked??

Code: Select all

GoToScreen #$13, #$01, #$02
I don't get it either. But as far as I can tell, writing the hex number for the specific screen in the grid, AS A NUMBER, is the correct name for that screen. Shrug.
I've now come to realize newScreen, currentScreen and warpToScreen all essentially hold the same value and any of them would have worked, if I had just known about the hex thing before.

So this is the Multi-tile. VERY UNTESTED at this time, so use with caution. If you find quirks and bugs I don't, maybe you can help by ironing them out.

Code: Select all

LDA currentScreen
    CMP #$01 ;; or whatever screen you want stuff to happen on...MUST BE IN HEX!!
    BNE trainstop1
    
    ;; enter your screen-specific shenanigans here
    
    trainstop1:
    LDA currentScreen
    CMP #$02 ;; or whatever screen you want stuff to happen on
    BNE trainstop2
    ; and on and on like this....
It might not even have to be a tile. Conceivably this could go in HandleScreenLoads, but i wouldn't know where. Dale might.

Keep in mind if you end up making the same commands for five screens or more, you might be better served creating an actual TILE for it, rather than repeating yourself. This is best used for limited actions.
But I'm psyched that I figured this out. An entire world of possibilities just opened up.
User avatar
TolerantX
Posts: 8
Joined: Fri Jan 18, 2019 7:58 am

Re: The Marvelous Multi-tile!

Post by TolerantX » Mon Apr 01, 2019 3:22 pm

Is there a way to have a trigger for every overworld screen, but not any underworld screen?
User avatar
Bucket Mouse
Posts: 316
Joined: Wed Mar 07, 2018 2:25 am

Re: The Marvelous Multi-tile!

Post by Bucket Mouse » Mon Apr 01, 2019 6:26 pm

TolerantX wrote:
Mon Apr 01, 2019 3:22 pm
Is there a way to have a trigger for every overworld screen, but not any underworld screen?
That one's rather simple, assuming we can find the variable that tells you which type of screen you're on.
After some searching I think it's update_screen_details....this is listed in System Variables:
; update_screen_details .dsb 1
; ;;10 = screen type, 00 = special, 01 = map1, 02 = map2

So you would put this before anything you wanted to only happen on the overworld....

Code: Select all

LDA update_screen_details
CMP #$01
BNE +
And for the underworld, that number would be #$02.
Post Reply