News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: Crystalis - Sky Tower Exit Hack  (Read 9617 times)

redmagejoe

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
Re: Crystalis - Sky Tower Exit Hack
« Reply #20 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.

redmagejoe

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
Re: Crystalis - Sky Tower Exit Hack
« Reply #21 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?

redmagejoe

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
Re: Crystalis - Sky Tower Exit Hack
« Reply #22 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/
« Last Edit: August 20, 2019, 09:20:49 am by redmagejoe »

Cyneprepou4uk

  • Full Member
  • ***
  • Posts: 161
  • Самый лысый ромхакер
    • View Profile
Re: Crystalis - Sky Tower Exit Hack
« Reply #23 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 or here, maybe we can work something out.
I am the baldest romhacker
NES Romhacking Guide

redmagejoe

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
Re: Crystalis - Sky Tower Exit Hack
« Reply #24 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.

Pennywise

  • Hero Member
  • *****
  • Posts: 2249
  • I'm curious
    • View Profile
    • Yojimbo's Translations
Re: Crystalis - Sky Tower Exit Hack
« Reply #25 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.

redmagejoe

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
Re: Crystalis - Sky Tower Exit Hack
« Reply #26 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.
« Last Edit: September 15, 2019, 07:08:09 pm by redmagejoe »