News:

Don't forget to visit the main site! There's lots of helpful docs, patches, and more!

Main Menu

Tying Door Indexes to Gates

Started by Mentlegen, December 09, 2017, 02:37:28 PM

Previous topic - Next topic

Mentlegen

Thanks to some helpful users i am now able to create remotely activated gates with H and V copy blocks. However, i would also like to learn how to tie gates to Door indexes. The Mod manual doesn't mention this, and i have only found one post about this topic.

Can someone please provide info on how to tie door indexes to gates or how to trigger door indexes with gates. 

I am trying to achieve a function similar to Hyper Metroid, as i have looked and found that the tourian gates all have high bit addresses corresponding with their respective switches, which sit on blocks with the same number ( eg tourian gate #15 has a high bit of 34, and the switch in maridia is sitting on a block with a red 34 on it )


Smiley

Short answer: You can't.

Slightly longer answer: You need custom ASM for that.

Mentlegen

Quote from: SMILEuser96 on December 09, 2017, 05:01:02 PM
Short answer: You can't.

Slightly longer answer: You need custom ASM for that.

okay, is there an asm file i can apply or do i need to write it myself?

and if i do need to write it, how hard is it?

Smiley

There's no public patch that does this as far as I know. Making it yourself wouldn't be that hard, though it will take a little while to learn how things work.
Here's how I would do this:
Create a new PLM that checks the door bit array, and then spawns either a closed gate or open gate depending on if a bit is set. Then the PLM would delete itself.
Both types of gates already exist (upside-down versions too!), which makes doing it this way really easy.

Here's a base for a null PLM you can start working on:
org $84EFE0 ;Location of PLM header. This PLM deletes itself and does nothing else
NullPLM:
DW Init : DW Main  ;Pointers to initialization code and the main instruction list

Init:
RTS

Main:
DW $86BC ;Deletes PLM

You should be able to do everything with the init code alone. Remember, check the door bit array, then spawn a new PLM depending on if a bit was set. You don't need to worry about removing the custom PLM because, as you can see, the main instruction list already does that.

That'll take care of the gate part checking a bit, but you still need something else to set those bits. Perhaps use the copy block trick you just learned to open off-screen grey doors?

Mentlegen

Quote from: SMILEuser96 on December 09, 2017, 08:33:34 PM
There's no public patch that does this as far as I know. Making it yourself wouldn't be that hard, though it will take a little while to learn how things work.
Here's how I would do this:
Create a new PLM that checks the door bit array, and then spawns either a closed gate or open gate depending on if a bit is set. Then the PLM would delete itself.
Both types of gates already exist (upside-down versions too!), which makes doing it this way really easy.

Here's a base for a null PLM you can start working on:
org $84EFE0 ;Location of PLM header. This PLM deletes itself and does nothing else
NullPLM:
DW Init : DW Main  ;Pointers to initialization code and the main instruction list

Init:
RTS

Main:
DW $86BC ;Deletes PLM

You should be able to do everything with the init code alone. Remember, check the door bit array, then spawn a new PLM depending on if a bit was set. You don't need to worry about removing the custom PLM because, as you can see, the main instruction list already does that.

That'll take care of the gate part checking a bit, but you still need something else to set those bits. Perhaps use the copy block trick you just learned to open off-screen grey doors?

Ok so I'm going to attempt this. Please tell me if i am on the right track.

So after looking at the RAM map, i found (7E:D8B0 - 7E:D8EF    Opened door bit array. D0-EF are never used)

So i'm going to need to write some code to set a bit that looks something like thisLoRom

org $7ED8D0
LDA ;loads value from 7ED8D0 into accumulator
CMP #$0001 ;Compare the loaded value which by def. is 0 with 1
BEQ END ;If the value is equal (aka already 1) go to subheading END
INC A ;increase the value of 7ED8D0 by 1 (if this line is read, then the value of 7ED8D0 is not 1, and by default it is zero, so unless externally set to another value, 7ED8D0 will only ever be 0 or 1)
RTS

END:
RTS ;End the routined the routine


This is my first ever ASM. So please be aware.

This code would set a bit at the door array, and would be run by the door switch. The next step would to be to modify the gate PLM code to read the address set above.

Smiley

CMP will do a comparison with the entire value, which is 16 bits large in this case. For doing comparisons with single bits, you'll need bitwise operations. I'm not going to explain them here in detail the game already has routines for whatever complex bitwise functions are needed. Just know that ORA is a bitwise 'or' operation, AND is a bitwise 'and' operation (wow really?)
INC will also increase the entire value by 1, not set a specific bit. A couple examples:
INC 0000 = 0001.
INC 0101 = 0110
INC 0111 = 1000
INC 1111 = 0000 (overflow)


Anyways, for setting a specific door bit, you'll need this routine:
80:818E 7E:05E7 = bit (A mod 8), X = A / 8. Most often used for testing or setting specific bits in a bit array.
So what you will want to do is load the door index to A, then jump to this routine with JSL. Then load the door bit array to A, indexed by X, and then set the door bit (currently defined in 7E:05E7) with ORA, and store the result back to the door bit array. So this is what the code looks like:
LDA !DoorIndex
JSL $80818E
LDA $7ED8B0, x : ORA $05E7 : STA $7ED8B0, x
RTS

Note that you don't need to necessarily check here if the bit is already set or not. If it's 0, it'll be set to 1. If it's already 1, it'll be set to 1 again, meaning it stays 1, so a check would be completely redundant.

For checking a door bit, you'll do largely the same thing, except you'll do AND instead of ORA, and then do a conditional branch. I'll just write the code for you:
LDA !DoorIndex
JSL $80818E
LDA $7ED8B0, x : AND $05E7 : BNE +  ;Branches if the bit was set
;Run code to spawn a closed gate here
RTS

+
;Run code to spawn an open gate here
RTS


And I'll just leave this here:
84:83D7 Creates PLMs. The routine that calls it must have after it the X and Y coordinate of the PLM and the address of the PLM header, in that order, after the JSL to 84:83D7. The PLM will be set up completely and run once. Then the code will resume, after those four bytes. If there are already too many PLMs and the game fails to make a new one, it just resumes code past those four bytes.
You can use DB to write a single byte, and DW to write a word (two bytes). (ex. DB $C8 : DW $1234)

Mentlegen

Quote from: SMILEuser96 on December 10, 2017, 06:41:02 AM
CMP will do a comparison with the entire value, which is 16 bits large in this case. For doing comparisons with single bits, you'll need bitwise operations. I'm not going to explain them here in detail the game already has routines for whatever complex bitwise functions are needed. Just know that ORA is a bitwise 'or' operation, AND is a bitwise 'and' operation (wow really?)
INC will also increase the entire value by 1, not set a specific bit. A couple examples:
INC 0000 = 0001.
INC 0101 = 0110
INC 0111 = 1000
INC 1111 = 0000 (overflow)


Anyways, for setting a specific door bit, you'll need this routine:
80:818E 7E:05E7 = bit (A mod 8), X = A / 8. Most often used for testing or setting specific bits in a bit array.
So what you will want to do is load the door index to A, then jump to this routine with JSL. Then load the door bit array to A, indexed by X, and then set the door bit (currently defined in 7E:05E7) with ORA, and store the result back to the door bit array. So this is what the code looks like:
LDA !DoorIndex
JSL $80818E
LDA $7ED8B0, x : ORA $05E7 : STA $7ED8B0, x
RTS

Note that you don't need to necessarily check here if the bit is already set or not. If it's 0, it'll be set to 1. If it's already 1, it'll be set to 1 again, meaning it stays 1, so a check would be completely redundant.

For checking a door bit, you'll do largely the same thing, except you'll do AND instead of ORA, and then do a conditional branch. I'll just write the code for you:
LDA !DoorIndex
JSL $80818E
LDA $7ED8B0, x : AND $05E7 : BNE +  ;Branches if the bit was set
;Run code to spawn a closed gate here
RTS

+
;Run code to spawn an open gate here
RTS


And I'll just leave this here:
84:83D7 Creates PLMs. The routine that calls it must have after it the X and Y coordinate of the PLM and the address of the PLM header, in that order, after the JSL to 84:83D7. The PLM will be set up completely and run once. Then the code will resume, after those four bytes. If there are already too many PLMs and the game fails to make a new one, it just resumes code past those four bytes.
You can use DB to write a single byte, and DW to write a word (two bytes). (ex. DB $C8 : DW $1234)

okay so using this code, i would spawn a closed gate or open gate at x(1) and y(1) in the room. I know that 7E:1C37 - 7E:1C86 is the PLM header table, but i don't know how to find the header for PLM C82A (open gate) and C826 (closed gate). these adresses would go right after the JSL $8483D7 
1 1 tho.

LDA !DoorIndex
JSL $80818E
LDA $7ED8B0, x : AND $05E7 : BNE +  ;Branches if the bit was set
JSL $8483D7 1 1 ;Run code to spawn a closed gate here
RTS

+
JSL $8483D7 1 1 ;Run code to spawn an open gate here
RTS