Romhacking.net

Romhacking => ROM Hacking Discussion => Topic started by: DrDimension on October 17, 2018, 10:40:12 pm

Title: Crystalis - Sky Tower Exit Hack
Post by: DrDimension on October 17, 2018, 10:40:12 pm
So a while back, I suggested in the hack idea megathread that someone create a patch for Crystalis that allowed you to return from the sky tower to earth (and vice versa). I've got a tiny bit of time now, and this seems like a relatively straight-forward hack, so I'm going to make the attempt.

As for what is required, I imagine the following needs to be done -

1) Find the offset for the sky tower map where I want the warp to earth tile to be (http://nesmaps.com/maps/Crystalis/CrystalisMap99.html).
2) Find the offset into the tile data that points the tile to the appropriate warp.
3) Understand the mapping of the tile data of the surrounding tiles so they can be edited to graphically indicate a warp tile.
4) Test that the Crystalis Sword can do damage to enemies on earth (EG, no (or very few) enemies are immune to it).

Again, this should be straight-forward, but we'll see.

If anyone wants to pitch in or make suggestions on any of the above, please feel free!

I'll post updates here.

October 18, 2018, 12:06:33 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Well, I found the offset of the tile I want to alter, but tile data in general doesn't seem to embed metadata such as warp destination.

Any suggestions how a game like this might correlate a tile with its warp metadata?

Thanks!
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: Rabite890 on October 18, 2018, 06:16:22 pm
Good luck on this. I've been upset about this ever since I played it back in 1991 or 1992.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: bmmpxf on April 22, 2019, 04:44:55 am
Sorry for reviving an old thread, but I have a lot to add to this that hasn't been said here or anywhere else.  I've actually implemented this as part of the Crystalis Randomizer (https://crystalisrandomizer.com).  It would be possible to backport it into a separate patch, and if anybody was actually interesting in doing so for this or any other features, I'd bbe more than happy to show you around my codebase and point you in the right direction.

As I've implemented it, you actually need to use Teleport or Warp Boots to get out (I didn't add a trigger, though that would also be possible).  It turns out another difficulty is that Draygon 2 will always spawn, even after you've killed him once (but the second time he's impossible because you used up your Bow of Truth already).  So to fix this you need to be able to make sure he doesn't respawn (it's quite possible, but requires moving some spawn conditions around to make space).

Crystalis does indeed do damage outside the tower, and is able to hit everything (immunities work by blacklisting elements, and Crystalis has no element).  But the charged shots only work in Dyna's room - I believe this is because that room fixes the player to only shoot upwards, and they only made sprites (and programming?) for that direction.  I haven't fully investigated this, and would like to make them work everywhere if possible (along with making it possible for Crystalis to break all walls and form bridges), though that's still quite a ways away from being reality.  (This would allow the randomizer to mix Crystalis into a different part of the game, other than the tower, which might be interesting).
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on April 22, 2019, 07:02:21 pm
I would just like to pitch in my support for this idea. I'm not averse to doing it myself, but I find myself with limited time of late, so if someone else wants to take up the torch... Your response, no matter how far from the last post, bmmpxf, is definitely appreciated. I'll be keeping an eye on this thread.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on May 23, 2019, 02:52:49 pm
I find myself with more time of late, so I think I can work on this project. Your assistance and input would be greatly appreciated bmmpxf. :)
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: steve_hacks on May 28, 2019, 06:32:27 pm
Your best bet would be to look at my disassembly in https://github.com/shicks/crystalis-randomizer/blob/master/Crystalis.st.  To make that useful, you'd need to clone the repo and use the `scripts/strip -r` utility to inject the bytes form the actual ROM into the stripped disassembly (I didn't want to publish the source publicly due to copyright, so the .st file is just the parts I've added).

Once you've got that, it should become a lot clearer what's happening.  Then if you look at the patches I've made [1, 2] to see how to put it together.

[1]: https://github.com/shicks/crystalis-randomizer/blob/d95ac98fb244952a91e89fe0bcd3590fca8234d0/src/js/preshuffle.s#L1002
[2]: https://github.com/shicks/crystalis-randomizer/blob/d95ac98fb244952a91e89fe0bcd3590fca8234d0/src/js/patch.ts#L579

What that amounts to is the following:
 (1) Changing PRG $3db39 (not counting the $10-byte header) to zero prevents jumping to the error when trying to teleport from inside the tower
 (2) Need to prevent draygon 2 from respawning after he's defeated.  This is harder because he doesn't currently have any spawn conditions, so you need to find some free space.  Draygon's spawn condition is at $1c955 (pointed to from $1c776.  You need to move that current block (4 bytes) into some unused space (possibly the middle of the spawn condition table, since those NPC IDs are unused) and then add a check for flag $28d in location $a6.

The best way to keep up with the latest in Crystalis rom hacking is the randomizer discord: https://discord.gg/ktyz5E6

~ steve/bmmpxf
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on May 29, 2019, 12:01:54 pm
Awesome, this will help a lot. I'll be sitting down and working on this starting tonight and report on my progress here.

In the process of doing this, I also decided to quickly make a version of the Computer Repair Patch (https://www.romhacking.net/hacks/4137/) that's compatible with the JPN version (God Slayer). I'll put a link up here once the submission is approved, and the RAR also contains a text file with the addresses in memory that were modified. The problem arises due to the fact that the English version has the addresses for the computer screen offset by -84 compared to the JP version, so the patch only worked for Crystalis. I reverse-engineered that patch and adapted it for God Slayer, so you can now play the JP version of the game translated and with the computer repair patch.

JP Computer Repair Patch released: http://www.romhacking.net/hacks/4533/



So my current priority list for this patch is, in order of easiest to implement to hardest:


With the 10-byte header, the address to change that allows Teleport to be used (in the US Crystalis ROM, which I'll be working with before adapting these to JP God Slayer) is 0x3DB43 from A5 to 00. However, for a single frame there's some garbage graphics that appear on screen before the teleport menu comes up. If possible I'd like to remove that to make it look more clean, but for now, I can at least check off #1 in that list.

https://i.imgur.com/nYQT0O9.png


I found a much cleaner fix after looking through the src provided by the strip script and comparing addresses with the slight offset. Since the instructions that begin with the A5 -> 00 change are checking player location, comparing player location to a value, and then if matching that value, going to the error instructions, rather than changing A5 to 00 at 0x3DB43 in the US binary, I simply changed the compare value line at 0x3DB36 (0x3DB46 in headered US Crystalis) from C9 58 (58 for Sky Tower) to C9 FF (FF which isn't any valid map ID and thus will never satisfy the critera of the BEQ) and it behaves like a normal teleport anywhere else. I'm going to go ahead and mark the teleport out priority addressed.

I have moved the MapData for rooms A7 (the room behind Draygon 2 in Pyramid) and 58 (the entrance of the Sky Tower) down to a large block of unused data directly after the MapData table, as I needed 4 bytes and 8 bytes of space. Rather than shifting the entire table 12 bytes and 1) making more work for myself by having to redo every pointer and 2) making compatibility with future patches more tiresome, I simply used the available space and changed the pointers for those two rooms, as well as the pointer table within each room's data to the appropriate addresses. The end result is a seamless transition from Pyramid to Sky Tower via the crystal. I'd like to look into making a Teleport spell effect rather than the default door behavior, but that may be a bit ambitious.

Stay tuned for working on making the Crystalis / God Slayer fully functional.



Working on making Crystalis / God Slayer work everywhere now, and once I'd navigated around the different blocks that handled weapon and object data, it became pretty easy to figure out what to do. At 0x35CDA (0x35CBA in headered US Crystalis) is A5 6C C9 5F D0 F1. I will break it down and explain how I changed this.

A5 6C stores the players current location, the map ID.
C9 5F compares this stored ID to 5F, which is the final boss / Dyna room
D0 F1 is a BNE (Branch on Not Equal) that ceases to progress the code for firing Crystalis shots if you are not in Dyna's room.

To remedy this, we change the C9 5F to C9 FF (or 0B or any other unused map ID), and change the BNE (D0) to a BEQ (F0) to make the Branch on Equal FF. Since these conditions can never be met, the Crystalis shot will work in all rooms in the game. I have also figured out how to make Crystalis shots fire in all directions, and not just up. It would seem that in the ObjectData for all sword beams...

Code: [Select]
ObjectData_WindAttack2                                   ; Object 11
        ;; Level 2 shot from Sword of Wind
        $1afff              .byte $33
        $1b000              .byte $ff,$18,$00,$0a,$02,$03,$1e,$00,$03
        $1b009              .byte $ff,$00,$02,$00,$10,$00,$11,$00,$00
        $1b012              .byte $88,$01,$1c
        $1b015              .byte $07,$01,$00,$01

... byte 06 on line 3 (so in this case, $11 on $1b009) determines the behavior of the projectile. Changing this 11 to 36 causes the Lvl 2 wind sword shot to behave like the Crystalis shot (always fire up), and conversely, changing this value in the Crystalis ObjectData from 36 to 11 causes it to fire in whatever direction you are aiming. The sprites are a bit buggy, but I'm currently working on that. For pure functionality, however, it is possible to fire Crystalis shots in any direction.

UPDATE: The patch is fully functional pragmatically. From a graphical polish standpoint, however, it needs work. In its current state, the Sky Tower is perfectly traversable at the player's leisure, the Crystalis/God Slayer can be used to fire in any direction, kills enemies, and interacts with elemental barriers. I'd like to touch everything up before I call it done, however.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: steve_hacks on June 03, 2019, 10:23:54 pm
Teleport should be a piece of cake - just change the entrance from $00 or $01 to $40 or $41.

That's interesting about the object data.  What you're changing is the object's "action script".  It's stored in $4a0,x and determines the routine that runs every (other?) frame for each object on the map.  It corresponds to an entry in the jump table at $36314.  In this case, $11 (most sword level 1 shots) goes to $370a8, while $10 (crystalis shot) goes to $370b5, which the former one falls through into after setting direction and graphics.  So in this case, that's probably exactly the right thing to do, though it might be possible to do some slightly different graphics in a currently-unused location and then jump to the same spot.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on June 04, 2019, 01:04:37 am
Teleport should be a piece of cake - just change the entrance from $00 or $01 to $40 or $41.

By changing the fourth byte in each exit, I did indeed get the screen effect of Teleport, but what I was aiming for was the actual sprite and SFX for Teleport. I don't know if there's a way to achieve this for these four (2 x 2 tiles on each side of the crystal) exits. Changing the fourth byte on the entrances doesn't seem to accomplish anything as far as I can tell... except for make the character invisible upon arrival.

That's interesting about the object data.  What you're changing is the object's "action script".  It's stored in $4a0,x and determines the routine that runs every (other?) frame for each object on the map.  It corresponds to an entry in the jump table at $36314.  In this case, $11 (most sword level 1 shots) goes to $370a8, while $10 (crystalis shot) goes to $370b5, which the former one falls through into after setting direction and graphics.  So in this case, that's probably exactly the right thing to do, though it might be possible to do some slightly different graphics in a currently-unused location and then jump to the same spot.

You had commented in your assembly that you weren't sure which of the two Crystalis Shots (1 and 2) were which, and I can tell you that Shot 1 is the large ball, and Shot 2 are the colored bubbles. $11 on Shot 1 makes it behave just like other sword shots, but the left and down graphics are bugged. $10 makes the ball maintain its shape in most directions, but it alternates every other frame with some garbage graphics. Modifying that action script byte on Shot 2 causes... weird things to happen. If I start looking through the action scripts a bit, I might be able to figure out how to get the ball to maintain its graphics.

Based on what you explained to me about action scripts, I tracked down these suckers in your disassembly.
Code: [Select]
ObjectActionJump_36
        $37070  a9 00:      lda #$00
        $37072  9d 60 03:   sta $0360,x
        $37075  bd 20 06:   lda $0620,x
        $37078  d0 44:      bne $370be
        $3707a  fe 20 06:   inc $0620,x
        $3707d  a0 00:      ldy #$00
        $3707f  a9 14:      lda #$14
        $37081  20 2d 97:   jsr AdHocSpawnObject
        $37084  90 38:      bcc $370be
        $37086  a4 10:      ldy $10
        $37088  b9 b0 00:   lda $00b0,y
        $3708b  18:         clc
        $3708c  69 18:      adc #$18
        $3708e  99 b0 00:   sta $00b0,y
        $37091  4c be b0:   jmp $370be
ObjectActionJump_11
        ;; The first frame, set the correct sprite for the direction
        $370a8  bd 60 03:   lda ObjectDirection,x
        $370ab  4a:         lsr
        $370ac  1d 00 03:   ora ObjectMetasprite,x
        $370af  9d 00 03:   sta ObjectMetasprite,x
        $370b2  de a0 04:   dec ObjectActionScript,x
ObjectActionJump_10
        ;; Subsequent frames, do normal thing:
        ;;  1. subtract 4 from 4e0
        ;;  2.
        $370b5  bd e0 04:   lda $04e0,x
        $370b8  38:         sec
        $370b9  e9 04:      sbc #$04
        $370bb  9d e0 04:   sta $04e0,x

This gives us the behavior for 11, 10, and 36... So I guess it's also possible that with this data we could... manipulate the way that 36 works rather than relying on changing the byte to 11? But then I guess that would be more work that still wouldn't address the sprite issue. Just thought it worth sharing though.

Also, while I'm better getting the hang of using pointers and moving data around, I reverted all the movement of the MapData for rooms 58 and A7, but I simply changed the pointers in their pointer tables for entrances and exits to the newly used space, and made the expanded entrance and exit lists in said space. No reason to copy all the data for the rooms, even the unchanged things, plus it uses up less of that juicy real estate beneath the MapData table that could be used for other modifications.



Before I get too caught up in sword sprites, enemy death sprites, and wall/waterbridge sprites, I'd like to focus on something in a similar vein. The final room prior to Mesia's room and Dyna's pre-room, the "top" of the Sky Tower, is a separate room, despite the main body of the tower appearing seamless. This is because rather than going through doors that have a fade-to-black transition, stepping over a threshold of the stairs leading up in each area noticeably blinks to transition to a brand new room. This causes the enemies in previous rooms to respawn, etc etc. Thus rooms 59, 5a, 5b, and 5c are actually 4 different rooms that appear to be 4 different floors in the same room of the Sky Tower. 5c, however, as mentioned being the one outside Mesia's room and the Dyna pre-room, has the stairs "vanish" behind the player after they enter. This is because that room is designed without stairs leading down, but there ARE two exit tiles two Y-coordinates down out of reach of the furthest the player can go in this room.

What I'm assuming I'm going to have to do is modify the MapScreen metatile data indexes, but I don't know where to begin comprehending it. I know that the existing exit tiles are at coordinates (18, 10) and (19, 10), with the bottom-most traversible tiles in 5c being (18, 0e) and (19, 0e). I am assuming that individual tiles are referenced in the metatile table that not only correlate to sprite data, but also whether the tile is walkable or not. I am ASSUMING (correct me if I'm wrong) that a single address dictates not only the sprite, but also the walkability. If my theory is correct, I should need only to change the appropriate addresses to those used by the rest of the stairs. I'm probably wrong though.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: steve_hacks on June 10, 2019, 03:47:33 am
Yes, changing the action scripts directly is the way to go.  Many of them muck with the metasprite (stored in $300,x, usually) based on direction, animation counters, etc.  The metasprite is an index into the metasprite table (pointer table at $3845c, data following).  Unfortunately the metasprite alone is not enough to understand the sprites, since it also depends on the active pattern tables and palettes (as stored in $7e0..$7e7 and $7f0..$7f5).

Background tiles are a similar story, in that the game treats them as metatiles.  There's actually a lot that goes on here.

The first 64K of PRG is map screens.  Each screen is a 15x16 grid of 16x16 pixel metatiles (a few are only 13x16, if they only ever show up on horizontal or single-screen maps).  This accounts for a full 240x256 pixels.  The game does some funny math so that objects' y-coordinates can never have an $f in the 16s place - i.e. the y-coordinate counts up 000, ..., 0ef, 100, ..., skipping 0f0...0ff.  Each metatile is 16x16, but the NES PPU's nametable uses 8x8 tiles, so this means that a metatile consists of 2x2 PPU tiles.  This is actually pretty convenient because the PPU also groups tiles into 2x2 blocks that share the same attributes (i.e. palette) so by mirroring this grouping, the game can avoid needing to worry about incompatible palettes between metatiles - each metatile now has a single dedicated paletted that's no longer shared with neighbors.  The MapData graphics subtable has two bytes that tell the game how to parse the metatiles: the tileset (a multiple of 4 between $80 and $ac) and the tileEffects (a number from $b3 to $bd).  For the most part there's a one-to-one mapping between tileset and tileEffects, except that tileset $a8 shares tileEffects $b5 with tileset $88, rather than incrementing to $bd like you would expect (you can see a full breakdown of this at https://crystalisrandomizer.com/stable/view/tileset).  The way this ends up working is as follows (and recall that the pattern tables are separate here, so this just maps to tile pattern IDs from 0..ff, and the mapping from there to specific CHR data is determined by the selected pattern table, and the colors by the selected palettes).

Suppose you have metatile T, tileset S, and tileEffects E
 * the metatile components tables run from $10000 to $12fff in $400-byte (1K) blocks, and gives four pattern IDs for each metatile.  The first $100 bytes is the top-left, followed by top-right, bottom-left, and bottom-right.
 * the metatile attribute table follows immediately after from $13000 to $132ff.  Each tileset gets a $40-byte block, with four metatiles' worth of palettes packed into each byte.  So each metatile gets two bits in this map (low-bits first - tile 0 of tileset $80 maps to ($13000) & $03, tile 1 to ($13000) & $0c, tile 2 to ($13000) & $30, etc), specifying which of the four selected background palettes to use for the tile.
* the tile effects table runs from $13300 to $13e00.  Each tileEffects gets a $100-byte block, which maps each metatile to an 8-bit value.  The bits have the following meanings:
    * $01 = pit (can fall into)
    * $02 = cannot walk over (but can maybe fly)
    * $04 = impassible (i.e. solid mountain)
    * $08 = has alternative (i.e. destroyable walls)
    * $10 = foreground tile (e.g. bridge you can go under)
    * $20 = slope (player will fall down)
    * $40 = slow (thick grass)
    * $80 = pain (marsh and spikes)
This is similar to but not exactly the same as the bits in $460,x for objects, which has to do with terrain susceptibility - I believe the bits $26 are at least the same in terms of what the object will walk on.  Note also that this is the *only* table indexed by E - all the others are indexed by S.
* the tile alternatives table runs from $13e00 to $13f7f.  Each tileset gets a $20-byte block mapping the first $20 metatiles to alternates that are swapped in if the mapdata flag is set (i.e. if the mapdata indicates that a screen has a flag, then that flag is used to determine whether to treat the metatile as the original (clear) or the alternate metatile (set).  This is used for clearing destroyable walls/bridges, locked doors (prison, stxy, swan), exploding caves (mezame shrine, sealed cave), as well as the angry sea and the door between the statues of sun and moon.  When used, the alternates affect both the graphics and the tile effects, obviously.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on June 10, 2019, 01:51:49 pm
It appears that during the execution of ObjectActionJump_36, it invariably jumps to _57. For the sake of science, I tried changing the action script flag on Crystalis from 36 to 57, and the end result is much cleaner. The orb retains its shape, doesn't flash, and I believe only has a minor artifact when firing left or right, with up and down shots looking flawless. Still, I can't get Shot2 to spawn without further experimentation, so working on that. I changed the flag back to $36 and have been tinkering with the script for $36. I changed the bytes starting at $37070 from A9 00 9D 60 03 BD 20 06 D0 44 to BD 60 03 9D 60 03 BD 20 06 EA. I essentially changed the LDA #$00 to LDA ObjectDirection,x used in $11. To make room for this, I needed to replace the BNE, whose purpose I'm not quite certain of other than to seemingly skip the generation of Shot2, with a single-byte instruction. I chose $EA No Operation, and now I can spawn Shot2. Currently they still only shoot up, and the graphics are only slightly wonky, but they also fire a second time from Shot1 traveling left or right after a certain interval. My hope is to reorient these bubbles to follow the path of the original orb rather than firing upward.

UPDATE: The Sky Tower is now 100% exit-ready with this patch in progress. The escalator on the last floor no longer vanishes behind you, Warp Boots and Teleport spell work in the entirety of Sky Tower (including the Dyna fight, unfortunately), and the crystal rooms in Sky Tower and Pyramid allow you to freely traverse the two locations. I'm currently trying to find a way to disable Teleport specifically in the Dyna fight, room 5F, but the check for your location seems to use a "base" location in its original state of $58 which I changed to $FF. Right now until I better figure out what the assembly instructions in that location are doing, it's either teleport in none of the tower or all of it. I'm going to update my priority list below.


I noticed that all of the checks for your location in the game that compare them to Dyna's Room (5f) generally follow the following model:

Code: [Select]
a5 6c:      lda CurrentLocation
c9 5f:      cmp #LOC_DYNA

However, for Teleport, it instead goes as such:

Code: [Select]
a5 6c:      lda CurrentLocation
29 f8:      and #$f8
c9 5f:      cmp #LOC_DYNA

This 29 F8 is an AND instruction that adds Accumlator and Memory into the Accumulator. As far as I can tell, this is checking not just the map ID, but a map "group" which includes 58, 59, 5a, 5b, 5c, 5d, 5e, and 5f. Thus by replacing 29 F8 with EA EA, two NOPs, Teleport should only check the room you are in. Thus we can teleport everywhere in Sky Tower except for Dyna's room with this change.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: steve_hacks on June 10, 2019, 11:43:09 pm
If you're mucking with action scripts and worried about space, I'd recommend finding some spare space in the back of the PRG (around $3f9ba) and JSR to it.  This will give you plenty of space to do whatever you need, without worrying about fitting exactly into the same area.

The teleport check in vanilla is `cmp #$58`, not `cmp #$5f`.  But you're correct that if you simply remove the `and #$f8` then you can simply compare against #$5f to have the desired effect.  But why do you care if the player teleports out while fighting Dyna?  Does that cause any problems?

I don't know how the player effect works teleport, but if you look at $3d31c (DialogFollowupActionJump_02_Disappear) you'll see how the sages (and Stom) disappear, which might give you some clue... unless you're thinking of something completely different.

For the backwards routes - does this cause any problems for keeping them closed until the white robots are killed?
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: Cyneprepou4uk on June 11, 2019, 03:01:26 am
BNE checks flag Z = 0 and jumps if true

AND doesn't add anything, it compares bits from memory and accumulator. Result is a byte, which have bit number = 1 if both bytes had the same bit number = 1, else 0
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on June 11, 2019, 12:36:10 pm
BNE checks flag Z = 0 and jumps if true

AND doesn't add anything, it compares bits from memory and accumulator. Result is a byte, which have bit number = 1 if both bytes had the same bit number = 1, else 0

Right, thanks for clarifying. I'm still pretty inexperienced at ASM, so I find myself trying to apply high level language analogs to what it's doing. I'll try to better keep in mind what's actually taking place from a processor standpoint.

If you're mucking with action scripts and worried about space, I'd recommend finding some spare space in the back of the PRG (around $3f9ba) and JSR to it.  This will give you plenty of space to do whatever you need, without worrying about fitting exactly into the same area.

The teleport check in vanilla is `cmp #$58`, not `cmp #$5f`.  But you're correct that if you simply remove the `and #$f8` then you can simply compare against #$5f to have the desired effect.  But why do you care if the player teleports out while fighting Dyna?  Does that cause any problems?

I don't know how the player effect works teleport, but if you look at $3d31c (DialogFollowupActionJump_02_Disappear) you'll see how the sages (and Stom) disappear, which might give you some clue... unless you're thinking of something completely different.

For the backwards routes - does this cause any problems for keeping them closed until the white robots are killed?

No problem, per se, but I do think that once you're actually in the final battle, by standards of games of the time it would be appropriate for the player to be properly locked into that fight without a teleport out.

And yeah, I did some copy-pasting shenanigans and had already changed that second chunk to $5f. I indeed achieved the desired results by removing the AND f8.

As for what I'm talking about with Teleport, the SFX and sprite effect that occurs where your character turns into a colored light silhouette and eventually into a wisp of nothing after using the Teleport spell, and then reversing that effect on arrival, is what I'd like to try to make happen when using the crystal exits between Pyramid and Sky Tower. That might be tricky to pull off, but I'll give it a try anyway.

Well the only route that's "closed off" in vanilla as far as I recall is room 5c, simply because I suppose that's intended to be a point of no return within a point of no return. I guess the devs didn't want the player to waste time going back and re-killing the robots or something, or taking the mostly non-functional Crystalis down to previous floors. It's most likely the latter, to make the only enemy you can use Crystalis on at that point Dyna. Or were you suggesting closing them off? I'd rather not tamper with that if possible.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: steve_hacks on June 13, 2019, 08:43:12 pm
Just wanted to make sure that opening the bottom exit of $5c doesn't open the staircases prematurely when you're going up.  I haven't figured out how opening the stairs works yet, but I did try an experiment where I replaced the robots with random enemies and the result was that all the stairs were just always open from the start, which is kinda disappointing.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on June 14, 2019, 02:38:18 pm
Oh no, because of the fact that the floors in Sky Tower are actually separate rooms, when you cross the threshold up the stairs, it simply reloads the screen with the new map even without the fade to black. It's just that 5c didn't have stairs going down, and I changed that in its tiledata. 5b, meanwhile, is completely unaffected by any of these changes because it's a different room. So 5b still has no stairs until the trigger is... well, triggered, by enemies being defeated, and the stairs then open up.

June 16, 2019, 03:53:49 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
I may need to call upon the assistance of someone who has worked with CHR ROM in NES games for assistance in this endeavor. Since I'm dealing with a sprite that is only programmed to work in one direction, someone who has some spriting experience would be very appreciated. :)
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on June 22, 2019, 05:23:00 pm
Just an update: I've been using FCEUX debugger and watching CHR memory to try and track down where in CHR ROM the projectiles for Crystalis / God Slayer are, but I'm still not sure how I should go about creating / modifying sprites to make a set of projectile sprites for the other 3 directions. Don't really have much experience in that regard, unfortunately. :-X
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: Cyneprepou4uk on June 22, 2019, 05:51:00 pm
put graphics in chr bank, check for a direction before firing a projectile and set 4 differend id's depending, add sprite attributes to a table for these new id's
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on June 22, 2019, 07:32:52 pm
put graphics in chr bank, check for a direction before firing a projectile and set 4 differend id's depending, add sprite attributes to a table for these new id's

Okay, I'll try to figure out how exactly I go about doing that. I apologize, I'm still pretty inexperienced but I do want to learn. :-[

EDIT: I'm reading over resources like this, not sure if it's entirely relevant, but I'll poke around! https://cppchriscpp.github.io/nes-starter-kit//guide/section_5/chr_ram.html
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: Cyneprepou4uk on June 23, 2019, 08:09:27 am
If you don't have chr ram, it is not relevant, but wouldn't hurt to study. However if you do, this changes tactics. You probably don't need to create more id's, that depends on how many tiles new projectiles will use. You also have to check for direction, but this time re-draw its tile in chr ram.

If an object can shoot several projectiles at once, or there can be several objects on screen shooting in different directions at the same time, better use my previous method.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on June 26, 2019, 10:33:29 pm
While working on this I also hit up Steve Hacks for a standalone version of the screen shake on message boxes fix that his randomizer comes with. He figured it would be best to push that as a standalone patch, so that may be coming down the line sometime soon. Taking another break on the CHR experimenting while I deal with some offline obligations, but I'm hoping to focus all of my attention to this again before long. Graphics are the only thing left to do before this patch can be released.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on July 17, 2019, 01:58:50 am
Considering that RL obligations have piled up again, and I've made no progress on this hack as a result, I'm contemplating putting it up as a v0.1 patch. I'd really like to see this through to its completion, but I also hate the idea that I might not be able to finish it for whatever reason down the line, and have the time and energy I put into it, coupled with Steve Hacks' awesome help, go to waste. If someone should want to carry on the torch and address the graphical aspect of this, at least they would have a baseline to work with, plus the functional end of this previously-requested hack would be out and available, albeit in a not-so-polished-cosmetically state.

Thoughts on this?
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on August 19, 2019, 05:45:46 pm
I've decided to upload the Screen Shake Fix, and I'll post a link in here as soon as it's cleared the queue. Likewise, I'm thinking I'll go ahead and upload my v0.1 of the Sky Tower Exit hack so that it's at least available. Don't know if there's really all that much interest in it, but I would appreciate it if anyone who might want to give me a hand in polishing it up would post in this thread. With a bit of guidance I can probably finish this up, but I've got zero experience working with graphics.

Screen Shake Fix: http://www.romhacking.net/hacks/4648/
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: Cyneprepou4uk on August 19, 2019, 07:55:08 pm
You mean helping you with those projectiles you were talking about 2 months ago?

Contact me here (https://vk.com/cyneprepou4uk) or here (https://t.me/cyneprepou4uk), maybe we can work something out.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on August 19, 2019, 08:36:16 pm
Yeah, from what I can see it seems like to do what I'd like to do would involve creating new graphics, or at the very least, creating a new orientation of existing graphics in a way that isn't already in the game's CHR ROM. Most of the other work is pretty much just making the ROM call existing graphics (namely the Thunder Sword graphics) when an enemy is killed, a wall is destroyed, and calling Water Sword graphics when an ice bridge is created.

I'll contact you with the disassembly I've got of a fresh ROM courtesy of Steve Hacks, and my WIP ROM with modified addresses. The patch is fully functional but just looks janky graphics wise when those previously mentioned situations arise, since the sword was never meant to be taken out of the tower.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: Pennywise on August 21, 2019, 09:34:03 am
As far as I know, this screen shake thing isn't a bug to be fixed in the game's code. It's an emulation bug that older, less accurate emulators mess up.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on September 15, 2019, 07:00:41 pm
https://drive.google.com/open?id=1h_m167MZ-0p6KSsceHREN2AATs5JnLY1

Decided to put the WIP patch up. As I've said, everything is functional, it's just some graphics that need touching up. If I find that I'm unable to move forward with this down the road, I'll put up all my notes and the emails I've gotten from Steve Hacks with information that might be crucial to polishing this up. In the meantime, it's here for anyone who wants to play around with it. This is only functional on the US Crystalis ROM, as I didn't get the chance to finish this and then port it for the JP ROM.

The last email I got from Steve in reply to one I sent before real life swamped me again:

Quote
I'm not sure where you found that code at $1fe7a, but it's definitely not relevant for you (though I'm glad you found it, since it's important for any renaming I might want to do).  The one place it's called from is MainGameModeJump_0c, which I believe has something to do with the status screen (when you hit "start").  What that code is doing is reading from the address table below ($1feb7) which has four entries pointing to 16-byte regions at $c0f0, $c5f0, $cef0, and $d7f0.  This is data packed in between the maps.  It takes $18 as input and loads that table (so the value will be 0..3), then reads from $0711,y, which is either $0711, $0712, $0713, or $0714 - so it's able to read *any* of the equipments (sword, magic, armor, shield).  If there's nothing in the slot (0711 is zero) then it starts at $c0f0 regardless of what $18 had (note the shift, since $10,$11 actually holds $f0,$80, but the bank switch to bank 6 made RAM $8000 point to PRG $c000).  The clc/adc is a common pattern - they clear carry so that the add works predictably.  So they add the equipment number to $11 and store it back.  (This is guaranteed to be a nonzero addition).  It then starts filling PRG RAM ($6010,x) with the loaded 16 bytes.  In this case, it's the equipment names (which makes sense given everything else).  $c0f0 is a bunch of spaces ($20), $c1f0 is "Sword of Wind", $c2f0 is "Sword of Fire", etc.  Note that the names are "encoded/compressed" with sprite indexes, so that $0a,$0b,$0c is "Sword", and $5c,$5d is " of " (with spaces).  Those are the sprites that make up the squished words (Sword, Magic, Armor, Shield, of).  It saves a little space, both in ROM and pixels.

In terms of where the sprites are plugged in, it's going to be in the object data, which is an address table at $1ac00.  Crystalis is entries $32 and $33 in that table, at $1b184 and $1b16c, respectively.  The entries in this table are laid out as follows: the first byte is the SFX it makes when it spawns (in this case, $75 for object $33 - you can listen to the different SFX by setting the accumulator to the number you want and then calling $3c125; I should totally make a rom hack that just exposes a debug room where you can play all the sounds and look at all the sprites).  Then follows four compressed sequences of 1 to 9 bytes that get filled into the object data table from $300 to $6ff.  This area stores 32 bytes of data for up to 32 objects.  Typically the object index (0..$1f) will be stored in X and then the game will look up (e.g.) $0300,x or $0320,x.  So this fills in all 32 of those numbers in turn, starting at $0300,x (this is what LoadOneObjectDataInternal actually does).  The compression scheme is basically the bits of the first byte of the sequence indicates which entries are filled in.  So if it's $ff (all 8 bits set) then it will read the next 8 bytes into $300,x, $320,x, $340,x, ..., $3e0,x.  If it's $80 then it will read only a single byte into $300,x.  If it's $01 then it will read only a single byte into $3e0,x.  Then it starts again with the second sequence populating the $400's, the third $500's, and the fourth $600's.

The relevant bits here are typically $300,x, which is the metasprite.  Sometimes the metasprite comes from $6e0,x or other places, but those are exceptions to the rule.  It looks like the two shots have $ff and $f9 there, which is interesting.  The metasprite ID is an index into the metasprite table, which is an address table at $3845c.  The $ff and $f9 entries point to $39041 and $38f8d, respectively.  The format of this table is a (typically) two-byte header (unless the sprite is a mirrored copy of a different one), with (1) the number of sprites S making up the metasprite, and (2) a mask for animation frames (assuming it's 2^n-1 then that means there's F=2^n total different frames).  Following the header is F blocks of 4*S bytes each, encoding each sprite in the metasprite with 4 bytes: (1) the x position (relative to the object's coordinate), (2) they position (relative to the object's coordinate), (3) the attribute values for the sprite (which palette to use and whether to horizontally or vertically flip), and (4) the actual ID of the sprite.  Most metasprites are monsters/NPCs, and the game loads their pattern tables in the third and fourth slot (look at $7f2..$7f5 in RAM for the currently loaded sprite pattern tables.  The zero slot in $7f2 is mostly fixed at $40 (unless you're slimed or changed) and holds the character's sprites, accessed with individual sprite IDs from 0..$3f.  The slot in $7f3 changes with the sword and is $42 for wind, $43 for fire, $44 for water, $45 for thunder, and $46 for crystalis.  Note that $7e4..$7e7 hold the color palettes, and again the second one ($7e5) goes with the sword, $01 for wind, $02 for fire, $03 for water, $04 for thunder, and $05 for crystalis.

You can see what the individual metasprites look like with a given set of patterns and color palettes by going to https://crystalisrandomizer.com/stable/view/sprites - except that I don't take into account what I just (re)learned tonight - that $320,x is used as an extra offset for the sprite ID, and crystalis' sprites have $c0 there, so for now you'd need to put the $46 into the third pattern slot to get it to display correctly - not sure what's up with that, except that possibly it's reusing the main ball's metasprite for dyna's counter wave (and the step counter is just kept constant so the animation doesn't trigger).

In any case, looking at all this what it tells me is that if you want to shoot in a different direction, you don't actually need more CHR space - what you need is more metasprites.  And a ton of extra ROM space: the balls have 8 frames and 9 sprites per frame, so that's 8*9*4 = 288 bytes.  To just make a horizontal version of this you'd need to double it.  To get it to not go "backwards" in two directions you'd either triple it and find a way to free up some adjacent metasprite IDs, or else quadruple it and jigger with the animation counter so that the upper bits stayed constant for any given direction.  I'm only aware of a single unused metasprite ID: $9a.  Though it's possible there are others out there.  I guess you could fix the "backwards" problem with an extra CHR page... as well as the particle problem, maybe.  Though I don't know for sure what else is on page $46.  The sword sprites are at $60..$63 for the big ball and $64..$68 for the small balls.  So it's just 9 sprites out of 64.  It looks like there's a bunch of unused ones at the end of that row, from $69..$6f.  You could possibly save a little space by cutting out the $68 sprite, which is a single colored pixel - that would reduce the sprite count from 9 to 7 - but that won't even buy you one extra direction, let alone three.  I also notice that there seems to be a redundant $64 sprite at the beginning of each frame - not sure what it's doing there, but it seems like you could safely get rid of that, too (it's overwritten at the same position with a $65 in every frame).

There *is* also 203 extra bytes at the end of that bank ($3bf35..$3cf00), but you'd need to get a little creative to use it.  If you drop down to 6 sprites, you only need 192 bytes per direction, a savings of 96, so the 203 could be plenty.  You could possibly manipulate the sprites to be a little more unidirectional, either by shrinking the top ball down into a little one, or growing the third one to be the same size as the others.

Another way to get more space would be to code up more compression.  I don't know how viable that is, given that this needs to be not very laggy, but in this case, a lot of the size comes from the multiple color palettes being used: the first four animation frames are identical to the second four, except with the palettes swapped (so the attr byte is XORed with 1).  If there were a way to indicate to do that without repeating the whole frame, then you could save some space - but plumbing that through would be exceedingly hard.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on November 04, 2019, 02:51:22 pm
I'm happy to see a number of downloads on the beta patch I put up, and I'm contemplating putting this up on the site proper as a pre-1.0 patch. That said, I feel this deserves more love than the time I have to dedicate to extensive patches anymore.

What would be the most appropriate procedure to follow if I were wishing to advertise/pass this project on to another member of the community? Is that in and of itself a faux pas? Thanks in advance, and again thank you to everyone who has helped a complete newbie like me with this project (Cyneprepou4uk, huge props to Steve Hacks who had all the knowledge while I was doing little more than applying his ideas).
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on December 11, 2019, 01:28:05 pm
http://www.romhacking.net/hacks/4831/

With this I formally discontinue my work on this project. Hopefully it is at least workable enough for those interested.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: lexluthermiester on December 15, 2019, 02:33:17 am
I just tried this out. It works as described and the very slight GFX glitches aside this is a fun hack. The game has always allowed a player to teleport away from the tower, but there was no way to get back. Now there is! Very cool stuff! 
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: redmagejoe on December 15, 2019, 12:10:07 pm
Thanks for the feedback lex. At least when I was testing, I could not get Teleport to work in any section of the tower and appeared to be completely locked in.
Title: Re: Crystalis - Sky Tower Exit Hack
Post by: lexluthermiester on December 17, 2019, 07:42:31 pm
Thanks for the feedback lex. At least when I was testing, I could not get Teleport to work in any section of the tower and appeared to be completely locked in.
I'm gonna have to retest that.... Hang on..

Oops. My bad. The only way to get off the tower was the Controller 2 warp.

Still, freaking awesome hack! Now if there was only a way to start the game with the Crystalis Sword... That would be a fun playthrough!