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

Author Topic: FF1 MMC5 Disassembly Updates  (Read 70139 times)

Jiggers

  • Full Member
  • ***
  • Posts: 248
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #380 on: July 08, 2019, 01:31:51 pm »
Thanks! I also forgot to make tents, cabins, and houses work on the safe tile, so I did that yesterday.

A few thoughts...

1. Bog tiles... Can't go any slower than normal walking speed, I think? Its already 1, dashing and boat is 2, airship is 4. I do want to add the forest effect to marsh tiles in the overworld though.

2. Haven't got a Switch so I don't know how BotW's springs work. A slow-healing tile, opposite the damage tile? Would just make people walk back and forth over it instead of using potions/spells/waiting to heal at springs... I think that might make gameplay a little dull when they appear. *shrug* If you meant like the hot springs in Earthbound/Mother 3 where you sit for a few seconds and then get the healing done, that might be better. But, would require a timer...1

3. I got Ice tiles working SO CLOSE, but I need to program in a "past" tile property routine first. Same for cracked floor tiles, since you want them to turn into teleport holes after you step off. For Ice tiles, I had it working so it would look ahead, and if the tile was ice, it would keep you moving. But this meant stepping close to an ice tile would trigger it. But if I put in a "compare ice tile to current tile" thing, then the first ice tile doesn't trigger! The next issue is that movement doesn't check if you can walk on the tile, so it allows you to slam yourself so hard into a wall you enter the wall. XD I think I can get it working after the "past" tile property is sorted out.

4. Bridge tiles--I'd like to do them! It would make dungeons so much cooler. But I think it would be best if they were single-space: A = bridge only lets you move left/right if sprite priority is above background, and up/down if sprite priority is below, and the opposite for || bridges. So no really wide bridges, basically... Sprite priority is set by the direction the tile was approached from, somehow.

5. On/Off blocks should be easy. Either a single variable is set and resets when the map changes, or each one works off its own game_flags event...?

Another way to do these ones is to make an object instead of a tile, but have the graphic be the same as the tile its mimicking. That would allow it to be visible/invisible!

6. On the subject of objects--That would be the best way to make push tiles, as well. I'm not going to look into that right now, because my brain hurts from everything else and it would involve poking at the NPC movement routines...

7. The torch... I'm iffy on that, because I hate total darkness, and because I don't know how palettes for maps work yet. What I'd prefer to see is more like... a lit torch colours tiles in a certain radius around it, while tiles outside its range are black/grey (but still visible enough to move around.) This is so out of my range, by the time I figure it out I will have forgotten about it.

8. Ladder tiles... will think about. If I can do the sprite-forcing!

9. Deep-water tiles sound great. A nice way to kind of make secret loot in dungeons that's impossible to get until later, so you have to back track...? I know some people hate that, but going to get all the mystic key loot is one of my favourite parts of the game. Except the Marsh Cave. Whatever's in there stays there.



1 I don't remember explaining my idea for an in-game clock. Whatever version of the NES this game uses, uses 60 fps, right? So every time it calls musicplay, it would increment the frame variable. At 60, that increments the second. At 60, that increments the minute. At 60, that increments the hour. At 99 it breaks.  :P And it only goes up when music is playing, so pausing, scene breaks, and all that, pauses the timer, which seems fair to me.

A timer could copy the seconds slot, and do a bit of math to see if X seconds passed, before triggering the mechanic...?
I know exactly what I'm doing. I just don't know what effect it's going to have.

Bregalad

  • Hero Member
  • *****
  • Posts: 2637
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #381 on: July 08, 2019, 03:11:52 pm »
I have not followed whether the dynamic action patch is used or not. But if it is I have a good idea, that is to use a Final Fantasy X style windows on the right edge of the battle screne, so that we can know in advance which heroes or monsters will have their turn in battle, and plan a strategy accordingly. This idea is pretty cool and would blend well with FF1 since there's not (yet) active-time battle.

Vanya

  • Hero Member
  • *****
  • Posts: 1489
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #382 on: July 08, 2019, 03:52:58 pm »
Whew! That's a lot. ;P

Thanks! I also forgot to make tents, cabins, and houses work on the safe tile, so I did that yesterday.

Shoot, I tested so quickly I forgot to even check for that. :P


Quote
1. Bog tiles... Can't go any slower than normal walking speed, I think? Its already 1, dashing and boat is 2, airship is 4. I do want to add the forest effect to marsh tiles in the overworld though.

Hmmm... It would have to be a bigger job than just changing the speed value.
I think the simplest thing would be to have an alternate routine that makes it so when you take a step it takes twice as long by adding a delay before you actually move out of the tile.
It would make you move at the same "speed" through the marshes, but your movement would be staggered.
It's like the party is pausing to carefully gauge where to step without sinking into the bog.

I fully support having the forest effect on swamp tiles! 100% :3


Quote
2. Haven't got a Switch so I don't know how BotW's springs work. A slow-healing tile, opposite the damage tile? Would just make people walk back and forth over it instead of using potions/spells/waiting to heal at springs... I think that might make gameplay a little dull when they appear. *shrug* If you meant like the hot springs in Earthbound/Mother 3 where you sit for a few seconds and then get the healing done, that might be better. But, would require a timer...1

It's kinds like the Earthbound one, but also like the total opposite of damage tiles.
Damage tiles cause some damage each time you step on one.
Hot spring tiles would cause some healing every few seconds after you stand still on them.
Like this sloppy pseudo-code:
1- Stepped on tile.
2- If countdown is at 0:
3- Set countdown timer to X.
4- If you leave the tile:
5- Jump to END.
6- Decrement countdown.
7- If countdown at 0:
8- restore 10-30 HP to each party member.
END.

Also, all water tiles you can walk in should have the forest effect.


Quote
3. I got Ice tiles working SO CLOSE, but I need to program in a "past" tile property routine first. Same for cracked floor tiles, since you want them to turn into teleport holes after you step off. For Ice tiles, I had it working so it would look ahead, and if the tile was ice, it would keep you moving. But this meant stepping close to an ice tile would trigger it. But if I put in a "compare ice tile to current tile" thing, then the first ice tile doesn't trigger! The next issue is that movement doesn't check if you can walk on the tile, so it allows you to slam yourself so hard into a wall you enter the wall. XD I think I can get it working after the "past" tile property is sorted out.

I imagine it should be simpler, (Says the guy who hasn't even looked at the relevant code).
When you step on the ice tile:
1- If the tile the sprite is facing is not solid: disable controller input and move the sprite in its facing direction without animating it.
2- If the tile the sprite is facing is Solid: enable controller input and allow movement as normal.
When you move off the ice tile:
1- If the tile the sprite is facing is not an ice tile: re-enable controller input.
(Alternatively, you could add a check to normal walkable tiles to re-enable controller input.)

That way the sprite keeps sliding until it hits a solid tile, but can move in a new direction once it has stopped. And it will slide onto normal tiles without continuing to slide after.


Quote
4. Bridge tiles--I'd like to do them! It would make dungeons so much cooler. But I think it would be best if they were single-space: A = bridge only lets you move left/right if sprite priority is above background, and up/down if sprite priority is below, and the opposite for || bridges. So no really wide bridges, basically... Sprite priority is set by the direction the tile was approached from, somehow.

I agree!!


Quote
5. On/Off blocks should be easy. Either a single variable is set and resets when the map changes, or each one works off its own game_flags event...?

Another way to do these ones is to make an object instead of a tile, but have the graphic be the same as the tile its mimicking. That would allow it to be visible/invisible!

Object ones might work for like single blocks, but I was thinking more along the lines of the mazes in Zelda 3 where you would have a ton of crisscrossing tile arrangements.


Quote
6. On the subject of objects--That would be the best way to make push tiles, as well. I'm not going to look into that right now, because my brain hurts from everything else and it would involve poking at the NPC movement routines...

Or a combination of tiles and objects, which (I think) is how Zelda 1 does it.


Quote
7. The torch... I'm iffy on that, because I hate total darkness, and because I don't know how palettes for maps work yet. What I'd prefer to see is more like... a lit torch colours tiles in a certain radius around it, while tiles outside its range are black/grey (but still visible enough to move around.) This is so out of my range, by the time I figure it out I will have forgotten about it.

Yeah, total darkness can be a drag.
As long as the tiles are ambiguous enough that you can still get lost it would be fine.
As for the effect itself, you're describing basically how the torch and radiant spell work in Dragon Quest.
I like it! It's more realistic really.
The torch in DQ only lights up adjacent tiles, but the Radiant spell has a radius of 3 tiles.
What do you think of this; add a torch battle item to the game (works like the one in DQ: radius 2) and a tile that you can light up with the torch (radius 4)?
And as an extra cherry on top, what if the lead character knows any fire or dia spell, they count as having a torch?


Quote
8. Ladder tiles... will think about. If I can do the sprite-forcing!

I would love it and like the bridge tile it woulds make dungeons more interesting! (See: FF Mystic Quest)


Quote
9. Deep-water tiles sound great. A nice way to kind of make secret loot in dungeons that's impossible to get until later, so you have to back track...? I know some people hate that, but going to get all the mystic key loot is one of my favourite parts of the game. Except the Marsh Cave. Whatever's in there stays there.

Anything that encourages more exploration is a great thing in my book!


Quote
1 I don't remember explaining my idea for an in-game clock. Whatever version of the NES this game uses, uses 60 fps, right? So every time it calls musicplay, it would increment the frame variable. At 60, that increments the second. At 60, that increments the minute. At 60, that increments the hour. At 99 it breaks.  :P And it only goes up when music is playing, so pausing, scene breaks, and all that, pauses the timer, which seems fair to me.

A timer could copy the seconds slot, and do a bit of math to see if X seconds passed, before triggering the mechanic...?

Clever! I like!! :3



I have not followed whether the dynamic action patch is used or not. But if it is I have a good idea, that is to use a Final Fantasy X style windows on the right edge of the battle screne, so that we can know in advance which heroes or monsters will have their turn in battle, and plan a strategy accordingly. This idea is pretty cool and would blend well with FF1 since there's not (yet) active-time battle.

The Dynamic Battle thing hasn't been implemented yet.
A turn order indicator would be nice.
I'd prefer it in the upper right of the screen as part of the round counter.
« Last Edit: July 08, 2019, 04:02:26 pm by Vanya »

Jiggers

  • Full Member
  • ***
  • Posts: 248
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #383 on: July 08, 2019, 04:53:30 pm »
Guests over this week, starting now... so my distraction level is 300%.

Turn order indicator might be interesting whether the action is dynamic or not... I think what I'd do is have start--instead of being auto-fight--swap between the turn # and the next entity to act, in the upper-right corner? Or even just pop up a whole box in the middle of the screen that shows the list, then goes away somehow. I really, someday, need to figure out how to do tricks like the dialogue box being on a different nametable and swapping it...

Ice tiles:

This is what I'm currently trying.

Code: [Select]
StandardMapMovement:
    LDA #$1E
    STA $2001             ; turn the PPU on

    JSR RedrawDoor        ; redraw an opening/closing door if necessary

    LDA $2002             ; reset PPU toggle (seems unnecessary, here)

    LDA move_speed        ; see if the player is moving
    BEQ SetSMScroll       ; if not, just skip ahead and set the scroll
                          ; the rest of this is only done during movement
      JSR SM_MovePlayer   ; Move the player in the desired direction
      LDA move_speed      ; move speed is 0 if a full tile has been moved
      BNE :+             
        LDA tileprop_now
        STA tileprop_last     ; copy the "now" tile properties to the "last"
        JSR CanPlayerMoveSM   ; see if the next tile is moveable
        BCS :+                ; if not, stop here
            LDA tileprop      ; get next tile properties
            AND #TP_SPEC_MASK ; mask out other stuff
            CMP #TP_SPEC_ICEFLOOR ; see if it ice tiles
            BNE :+                ; if not, skip all this
                CMP tileprop_last ; compare to last tile
                BNE :+            ; if the same, continue moving on the slippery path; if not, stop

              LDA #2          ; move faster on slippery stuff
              STA move_speed
              STA mapdraw_job ; and set mapdraw_job to keep drawing new tiles ahead
     
    : JSR MapPoisonDamage   ; do poison damage

      LDA tileprop          ; get the properties for this tile
      AND #TP_SPEC_MASK     ; mask out the special bits
      CMP #TP_SPEC_DAMAGE   ; see if it's a damage tile (frost/lava)
      BNE :+                ; if it is...
        JMP MapTileDamage   ;  ... do map tile damage
  :   RTS

It's not going very well so far! mapdraw_job is specifically not updating once you start sliding, but sliding is starting at random, sometimes passes through solid tiles (but usually stops if the next tile is not solid and not an ice tile)...

I also did this:

Code: [Select]
DoMapDrawJob:
    LDA $2002           ; reset PPU toggle  (seems odd to do here...)

    DEC mapdraw_job
    LDA mapdraw_job     ; find which job we're to do
    ;SEC
    ;SBC #1              ; decrement the job (to mark this job as complete
    ;STA mapdraw_job     ;   and to move to the next job)

    BEQ @Attributes     ; if original job was 1 (0 after decrement)... do attributes

    CMP #1              ; otherwise, if original job was 2 (1 after decrement)
    BEQ @Tiles          ;   ... do a row/column of tiles

    RTS                 ; if job was neither of those, do nothing and just exit

  @Tiles:
    JSR DrawMapRowCol       ; draw a row or column of tiles
    RTS                     ;  and exit

  @Attributes:
    JSR DrawMapAttributes   ; draw attributes
    RTS                     ;  and exit

Which shouldn't really change its behavior, just save a few bytes, right? I think it works, because walking normally still updates just fine... so its something else.
« Last Edit: July 08, 2019, 06:17:43 pm by Jiggers »
I know exactly what I'm doing. I just don't know what effect it's going to have.

Vanya

  • Hero Member
  • *****
  • Posts: 1489
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #384 on: July 08, 2019, 06:12:09 pm »
No worries! Attend to your guests!
« Last Edit: July 08, 2019, 07:59:48 pm by Vanya »

Jiggers

  • Full Member
  • ***
  • Posts: 248
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #385 on: July 08, 2019, 07:47:36 pm »
Its in 1F/fixed bank! Think you found it though.

Reason I'm fiddling with StandardMapMovement is that, when its done, move_speed is set to 0. For ice tiles to keep the player moving, move_speed has to be set back to 1 (or 2 so it feels more out of control).

I might be over-thinking it again... gonna try simplifying it.



Mneghhh...

Code: [Select]
StandardMapMovement:
    LDA #$1E
    STA $2001             ; turn the PPU on

    JSR RedrawDoor        ; redraw an opening/closing door if necessary

    LDA $2002             ; reset PPU toggle (seems unnecessary, here)

    LDA move_speed        ; see if the player is moving
    BEQ @CheckIceTile
    ;BEQ SetSMScroll       ; if not, just skip ahead and set the scroll
                           ; the rest of this is only done during movement
      JSR SM_MovePlayer    ; Move the player in the desired direction
    : JSR MapPoisonDamage  ; do poison damage

      LDA tileprop          ; get the properties for this tile
      AND #TP_SPEC_MASK     ; mask out the special bits
      CMP #TP_SPEC_DAMAGE   ; see if it's a damage tile (frost/lava)
      BNE :+                ; if it is...
        JMP MapTileDamage   ;  ... do map tile damage
  :   RTS

  @CheckIceTile:
   LDA tileprop_now      ; this is set every time it draws the sprites
   AND #TP_SPEC_MASK     ; mask out other stuff
   CMP #TP_SPEC_ICEFLOOR ; see if currently standing on ice tile
   BNE SetSMScroll       ; if not, set scroll
       JSR CanPlayerMoveSM  ; see if the next tile is moveable to
       BCS SetSMScroll      ; if not, set scroll
         LDA #2          ; move faster on slippery stuff
         STA move_speed
         STA mapdraw_job ; and set mapdraw_job to keep drawing new tiles ahead
  ;; flow into SetSMScroll

Still not working right. Feeling pretty stumped.

Some new poking around and I've discovered... I probably don't need to set mapdraw_job, that's done by StartMapMove. Also, you can control yourself in a slide, so I will have to disable that as well...

But after this much frustration I think I'll just focus on another tile type...
« Last Edit: July 08, 2019, 09:42:10 pm by Jiggers »
I know exactly what I'm doing. I just don't know what effect it's going to have.

Vanya

  • Hero Member
  • *****
  • Posts: 1489
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #386 on: July 08, 2019, 10:24:06 pm »
Its in 1F/fixed bank! Think you found it though.

Reason I'm fiddling with StandardMapMovement is that, when its done, move_speed is set to 0. For ice tiles to keep the player moving, move_speed has to be set back to 1 (or 2 so it feels more out of control).

I might be over-thinking it again... gonna try simplifying it.

Maybe so.


Mneghhh...

Still not working right. Feeling pretty stumped.

Some new poking around and I've discovered... I probably don't need to set mapdraw_job, that's done by StartMapMove. Also, you can control yourself in a slide, so I will have to disable that as well...

But after this much frustration I think I'll just focus on another tile type...

I'm looking over all the routines in that area.

Maybe it would be easier to integrate it into the existing routines?

In lut_SMMoveJmpTbl:
Add a new entry for ice tiles -> SMMove_Ice.

In SMMove_Ice:
Set the ice tile flag on.
CLC to allow movement.
RTS directly back.

In SMMove_OK:
Set the ice tile flag to off before the CLC.
This will ensure that you can't slide into any non-ice tiles.

In CanPlayerMoveSM:
@CantMove:
Set the ice tile flag off.
This will ensure that you can't slide into solid things.

In DashButton:
@Walking:
Add a check for the ice tile flag.
If it's on, set move_speed = 2.
Otherwise proceed as normal.

In SMMove_Right:
In SMMove_Left:
In SMMove_Down:
In SMMove_Up:
@FullTile:
Add a JSR to a new subroutine -> SMIce_Check.
Add a check for the ice tile flag.
If it's on, skip over the STA move_speed so that movement continues.
Proceed as normal to reset the move counter so that we can move to the next tile.

In SMIce_Check:
JSR to CanPlayerMoveSM.
If there is another ice tile, the ice tile flag will remain on.
If there isn't another ice tile, the ice tile flag will get turned off.
This extra check prevents sliding into things that you shouldn't.
RTS back @FullTile.


It's not as clean as doing it all in one place, but it might get the job done.

This set up "should" make you keep moving once you are on an ice tile that has at least one other ice tile in that same direction without allowing any input since you're never going back into the ProcessSMInput routine while there is still ice for you to move on to.

You should always stop if there is an object, a no-move tile, or a non-ice tile in front of you; since in those instances the flag will go down and the move speed will reset to 0.

So you should never slide into normal floors or walls or people or... at least that's what I hope would happen.
« Last Edit: July 10, 2019, 11:55:25 pm by Vanya »

Jiggers

  • Full Member
  • ***
  • Posts: 248
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #387 on: July 17, 2019, 10:46:47 am »
Thanks, I'll try it in a few days, whenever I get around to it...! Unless you've already tried it?

(Another difficulty I ran into while working on bridges, is that the fixed bank is again overflowing... need to move some non-vital things around again before resuming work on tile properties.)

Vacation times are over so life should be getting back on track. Ear infections and summer nights too damn hot to sleep. One of those things has paid off somewhat:

I reverse-engineered the Dynamic Action patch and put the changes into a vanilla Bank C file. I hope this is allowed... I figure that'll help Vanya put it in later, or I'll figure out how to update it myself at some point.

What I'd like to figure out at the moment is if I'm using the best disassembler for the job. I used 6502d, which helpfully put in  all the offset stuff. I tried another one that split the rom up into banks, but then lacked further information...

Then I compared the vanilla game with the patched game's ASM, but that was a nightmare. Notepad++'s compare plugin crashed... guess it couldn't handle having so many lines in the files? They ended up being almost 4 megabytes. I tried Meld, but that doesn't work in Windows 7. I ended up using Diffuse, but... maybe because of the offset numbers being different... when a bit of code is moved from its original location, it reads as entirely new code, so it was a hassle to really see ONLY the additions.

I've got a rom with a bunch of anomie's patches, for instance, and Diffuse basically throws up a difference list that looks like 80% of the game is changed, which I'm sure is just a result of bits getting shifted a few bytes and otherwise remaining the same. Still, too much effort to sift through that. So what can I do to make the process easier?

This isn't for the MMC5 project--I just wanna help the guy who wants the poison messaging with the dynamic action patch and anomie's bug fixes and enemy poison patch.

Edit: turns out he did a lot more than just anomie's bug fixes! So nevermind all that for now, I'll sort it out somehow, sometime. Mayyybe.



Another question! So I've noticed in a few places the game uses like, BNE, BEQ, BCC, BCS, those things, as a kind of JMP--it will always branch in these circumstances. I thought this was kind of weird, because looking at the disassembler in emulators, it SEEMS like it takes up the same amount of bytes, right? Three; one for JMP, two for the address. But then in the disassembly, it shows the bytes that make up the ASM code, and its like... 2?? Because all those branches can't reach further than $FF bytes away, right? So its not weird to do this, its smart? So--but like, how does it work, how does it know which direction to branch in once its pure hex?

If you BNE to a label that's higher up, does that use like, $00 to $7F? and then labels further down are $80 to $FF? (or the opposite?) So its not really able to branch further than $7F, but it can go both ways from the branch point? Or is it somehow $FF bytes from the branch point, but uses an extra byte to go in reverse?



https://youtu.be/YHz3pZbK4s8

Update! Bridges and deep water tiles work. Give 'em a go in Coneria! I'll be looking around each town to see if rivers are okay to walk in; if so, I'll leave it like this. Edit: Yeah, Onrac has water tiles for the ocean, you walk out there and its green on the other side. Woops!

One thing I'd like to fix up later, is when the sprite hiding toggles. Right now its instant; hides your lower half when you start to move. When getting out from under bridges or out of water, it waits 'til the move is halfway done before switching it off... Lemme know if it should behave different? It might look weird being behind some tiles when climbing out of the water.

Maybe eventually you can only get into water from a stair tile...

Update 2... 3... 4, 5?  :D

Onrac's town map is changed some. I was able to make an "ocean" tile out of an unused door, which happily uses the deep blue palette for dialogue boxes. I added more stream shadows to places, since the original was sloppy about where to use them. I fixed up the trees in the upper left where you can see the map wrap around... And added a smattering of sandy tiles to say... hey. This is the shore. That's the Ocean.

« Last Edit: July 18, 2019, 01:33:43 am by Jiggers »
I know exactly what I'm doing. I just don't know what effect it's going to have.

Vanya

  • Hero Member
  • *****
  • Posts: 1489
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #388 on: July 18, 2019, 03:59:56 am »
OK, wow. That's a lot. I'll check things out in more detail tomorrow.
About the branching opcodes, I was under the impression that they mostly just skip forward a short ditance, not backwards, but I'll have to look that up so grain of salt and all that.

Cyneprepou4uk

  • Full Member
  • ***
  • Posts: 161
  • Самый лысый ромхакер
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #389 on: July 18, 2019, 04:44:40 am »
Branch instructions jump foward with positive bytes and backward with negative. Base address is an address of the following instruction, byte from branch instruction is an offset value. You can understand it better when changing byte and looking at debugger. Lots of games use branches with preset condition instead of jumps to save some space.
I am the baldest romhacker
NES Romhacking Guide

Vanya

  • Hero Member
  • *****
  • Posts: 1489
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #390 on: July 18, 2019, 08:51:04 am »
Cool, thanks! :)
I knew there was a lot I wasn't remembering.

Jiggers

  • Full Member
  • ***
  • Posts: 248
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #391 on: July 20, 2019, 02:54:16 pm »
Hm... so



Negative bytes are over $7F? Checking a few BNEs, they're all $D0--I thought maybe its like... $D0 for branching backwards, $D1 for branching forwards, and the assembler decides which BNE to use based on where the label is. That would allow for double the reach! But so far if its going backwards its a real high number, and going forwards is usually pretty low.

OH. THAT'S WHAT THE NEGATIVE FLAG MEANS.

I'm not sure if its in the master branch right now or if its something I did after that I haven't uploaded yet, but all the doors everywhere are being treated like a weapons shop... So that's urgent... Fixed it.

Enemies are not using the right graphics. Zombulls are Iguanas, trolls are giants. Weird.
« Last Edit: July 20, 2019, 03:41:07 pm by Jiggers »
I know exactly what I'm doing. I just don't know what effect it's going to have.

Vanya

  • Hero Member
  • *****
  • Posts: 1489
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #392 on: July 20, 2019, 05:27:53 pm »
Don't branches work by skipping up or down a certain number of lines?
Generally speaking when you skip down say 3 lines the value used is 3, but if skipping up it's 7f+3 thus using the value 82 or some such like that?

Jiggers

  • Full Member
  • ***
  • Posts: 248
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #393 on: July 20, 2019, 07:44:34 pm »
First half is correct, second half is ... weird! In that picture, it says $FB, but its only going back 3 or so bytes. So #7F would skip ahead that many bytes... but $80 would skip backwards $7F bytes too? I dunno. As my friend explained it: "Anything past byte 127 is a negative. So 128 is actually -128"

I managed to wrangle some code into some other code, freeing up 175 bytes (aw, only 166 now) in the fixed bank! Overworld movement and map movement was basically the same, except it changed ow_scroll instead of sm_scroll and such tiny changes like that. So I put in a bunch of checks for overworld vs. maps and its all working nicely. Next I just gotta adjust the way forest tiles hide the sprites--

I've got it working now so that hiding/unhiding always happens at 8 pixels into the move, so the bottom half of the sprite doesn't vanish the very second you start to go into water. It still looks a little awkward sometimes, walking into a bridge, but its better than it was?

Question: The player sprite is always first loaded. Does that mean it will be on top of other sprites, or beneath them, if they collide? If I could make bridges (in dungeons anyway!) just be sprites, that would look so much cleaner.



Something's seriously wonky with enemy graphics. Ankylos load up Lich graphics, gators and caribes are wolves and imps instead, trolls and bulls are iguanas and giants...

I don't remember where all the enemy graphic loading stuff is, either...


Found the issue. My bad. LSR and ASL look so similar sometimes.



Okay, figured out mostly how to do slow swamp tiles on the overworld. There is an issue with attributes, though. Check OverworldMovement to see what I did.

Basically, uses the frame counter to skip moving the player. Theoretically, it should behave the same as having no movement speed? But for some reason, moving up and down doesn't update the colour of new tiles when moving slow! Left and right is fine.

So I think, okay, I'll just have it update the attributes when moving! But that makes moving left/right not update them right? It's updating them too much maybe? Whatever--so I add in a check. If left/right, no update. If up/down, update. And that works, until you change directions. I don't know what is going on at this point.

Ideally, ignore all the attribute stuff and just ... do nothing, for a frame? do we have to set scroll...? Hm...

Edit again:

Fixed that. Put the frame counter after the JSR to OverworldMovement, then -- oh gah I forgot to make it update audio, this is hilarious...

https://youtu.be/prIsMVx2oLQ

It's okay I fixed it now.

Final Update:

Marsh tiles cover the bottom half of the player, and slow them.
Forest sides and bottoms cover the bottom half of the player (sides look weird though still)
Movement speed is reduced in all deserts, including the caravan, but not when entering the wind tower (that would make it a raise airship tile).
Movement speed is reduced entering holes and climbing the volcano.
Movement speed reduction is active on non-battle tiles and battle-tiles... but I don't think setting it on ocean tiles or river will work? Not sure!
« Last Edit: July 21, 2019, 03:58:11 am by Jiggers »
I know exactly what I'm doing. I just don't know what effect it's going to have.

Disch

  • Hero Member
  • *****
  • Posts: 2717
  • NES Junkie
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #394 on: July 21, 2019, 02:36:38 am »
To explain the branching behavior, sounds like you guys need a lesson in 2's compliment!

Each digit in a numbering system has a "weight".  In our normal decimal system, the "ones" place has a weight of 1 (or 10^0), the "tens" place has weight of 10 (10^1), "hundreds" has a weight of 100 (10^2), and so on.

The number 142 can be deconstructed as so:
(2 * 10^0) + (4 * 10^1) + (1 * 10^2)

Similarly, in binary, each bit has a weight, but rather than being 10 to a power, it's 2 to a power.

So the binary number 101 is:
(1 * 2^0) + (0 * 2^1) + (1 * 2^2)
= (1 * 1) + 0 + (1 * 4)
= 1 + 4
= 5


"2s compliment" is a way to represent negative numbers by tweaking this ever so slightly -- by making the highest bit a negative weight.  So with an 8 bit number, instead of bit 7 having a weight of 2^7, it would have a weight of negative (2^7).

So the number %10000001 would be:
(1 * 2^0) +  (1 * -(2^7))
= 1 + (1 * -128)
= -127

This changes the effective range of a single byte from [0,255] to [-128,127]

This is how branches work.  The byte is a 2's complement representation of how many bytes to skip.  If that number is negative, it'll jump backwards.


2's complement has some really neat properties, too.  Two of the coolest are:

1)  It wraps properly.  Adding 1 to 127 (overflowing) will result in the lowest possible number (-128)

2)  It ends up being completely inconsequential when arithmetic is bounded to a certain byte size.

That second one is especially neat.  Let's say you get fancy and want to add $64 + $FF, but your solution has to be in a single byte.  You would expect $64+$FF to get you $163, and then for the high byte to get dropped so you clip to a single byte, resulting in $63.

But note that $64 - 1 is ALSO $63.  So the relationship between $FF and -1 so perfectly natural that you never really even have to think about it.


EDIT:  And, yes, this is basically why the "negative" N flag on the 6502 basically just means "high bit is set".  Because any value with its highest bit set is a negative number in 2's complement.

Vanya

  • Hero Member
  • *****
  • Posts: 1489
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #395 on: July 21, 2019, 07:17:29 am »
I knew it was something like that. but I never heard it explained like that before.
Groovy.

Jiggers

  • Full Member
  • ***
  • Posts: 248
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #396 on: July 21, 2019, 09:56:22 pm »
The mathy-lookin' bits go over my head... But I think you're just saying what I already figured out? :D And funny... I've been using $FF as -1 for a while, but I still sometimes don't really think about it as being -1...

Another question: Sometimes I see a ~ in things, like this:

Code: [Select]
    LDA mapflags         ; turn off the 'draw column' map flag
    AND #~$02            ; to indicate we want to draw a row
    STA mapflags

What's the purpose of that?

And I sort of get what this one is doing... but I wonder how it does it.

Code: [Select]
MapPoisonDamage:           ; first thing is to check if ANY characters are poisoned.
    LDA ch_ailments              ; if nobody is poisoned, do nothing.
    CMP #04                      ; get char 0's ailments... see if they=4 (poison)
    BEQ @DoIt                    ; if yes... "DoIt"

    LDA ch_ailments + (1<<6)     ; and do the same with chars 1,2 and 3
    CMP #04
    BEQ @DoIt
    LDA ch_ailments + (2<<6)
    CMP #04
    BEQ @DoIt
    LDA ch_ailments + (3<<6)
    CMP #04
    BEQ @DoIt



Big new update! I've been busy today!

* Chicken Knife and Brave Blade exist in the code. Only the Chicken Knife can be found in the game so far. Chicken Knife's damage = how many battles have been run from (caps at 255). Brave Blade's damage = how many battles have been won. Is not effected by character's base damage. I've given the Chicken Knife catagory effectiveness against giants and werebeasts, and the Brave Blade's is against dragons and undead. Their accuracy is slightly less than the Masamune and Excalibur. The thief cannot equip the Brave, nor can the white/black mages or wizards. The Blackbelt and Master cannot equip either weapon; but everyone else can use the knife.

* There's a new hidden character stat, "damagebackup" to be used by the Chicken Knife and Brave Blade. Equipping one (even just briefly pointing the cursor at it counts as equipping) copy-pastes the damage stat to it, and turns it back when unequipping. Otherwise things get REAL screwy.

* I made a new tile, Water Access. In towns, this is the stair tile, but being under a bridge and in water also grants it. It is taken away after moving, unless you've moved into more water, more stairs, or under another bridge. The effect is that you can only get into water from under a bridge or by stairs.

* I've changed the Coneria town map to put a Water Access stair tile in...! Explore!

* I changed the overworld marsh tiles to have some black in them. I think it makes them look more marshy, brambly... and it helps to see glimpses of the character sprite when they're sunk.

* I re-fixed the treasure chest tiles... I broke them when I changed them from $09 to $19 (and then had them listed as $99 so you can't walk on them; this is still necessary, but it no longer breaks them.)

* I fixed another issue with stealing. I had to copy-paste some code, but now there's 2 tables, one for normal items, one for special items. Instead of 1 table that's $200 bytes long and would require me to be smarter than I am about how to use it... Think this is why I stole a "blank" from Kraken...
I know exactly what I'm doing. I just don't know what effect it's going to have.

Vanya

  • Hero Member
  • *****
  • Posts: 1489
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #397 on: July 22, 2019, 07:33:15 am »
Cool beans!
Are you planning to add any other weapon effects to the game?
I can't think of any I'd want off the top of my head.
How many can be added?

Disch

  • Hero Member
  • *****
  • Posts: 2717
  • NES Junkie
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #398 on: July 22, 2019, 10:41:38 am »
~ is the complement operator.  It flips all bits in the given value.  Effectively a XOR with $FF

~$02 = $FD

It's often used with AND for clarity, as it communicates "I want to turn this bit off", making it a direct counterpoint to ORA:

Code: [Select]
ORA #$01  ; "Set the low bit"
AND #~$01 ; "Clear the low bit"

Jiggers

  • Full Member
  • ***
  • Posts: 248
    • View Profile
Re: FF1 MMC5 Disassembly Updates
« Reply #399 on: July 23, 2019, 02:19:59 pm »
Ohhh... so removing the ~ would be a terrible idea, then, without changing anything else. I get it. XD There's a few places I could have used that for clarity instead of doing whatever else I did...

Cool beans!
Are you planning to add any other weapon effects to the game?
I can't think of any I'd want off the top of my head.
How many can be added?

Definitely not planning anything. The weapon category/effectiveness stuff is barely used as it is. The Chicken and Brave ones are hard-coded to act this way. Any other crazy stuff like having a weapon's accuracy be a character's intelligence stat or something, would have to be hard-coded as well.

22 weapons can still be put in, as well.

Gonna take a break from tilework to maybe start playing again? :P

July 25, 2019, 01:04:27 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Here's an experiment:

Code: [Select]
Battle_CastMagicOnEnemyThenSelf:
    ;JSR Battle_CastMagicOnEnemy

    JSR BtlMag_LoadEnemyDefenderStats   ; load enemy stats into defender mem
    LDX #MATHBUF_MAGDEFENDERHP          ; backup the enemy's current HP
    LDY #MATHBUF_AILMENTCHANCE          ; and save it as "ailment chance" which shouldn't be used by damage spells
    JSR MathBuf_CopyXToY
    JSR :-                              ; JSR back to do the following JSRs, thus saving 3 bytes
  ;  JSR BtlMag_PerformSpellEffect       ; do the spell (modifying defender's stats)
  ;  JSR BtlMag_SaveEnemyDefenderStats   ; update changed enemy stats.
   
    JSR TargetSelf                      ; now target the caster
   
    LDX #MATHBUF_AILMENTCHANCE          ; compare enemy's HP pre-damage
    LDY #MATHBUF_BASEDAMAGE             ; to the amount of damage done
    JSR MathBuf_Compare
      BCC :+                            ; C = set if Y >= X, clear if Y < X
   
    LDA math_ailmentchance              ; if damage is greater than HP, take their HP
    STA math_basedamage                 ; and save as the max damage to heal; only one byte since healing caps at 255

  : LDA #$13                            ; now load up the effect for Drain healing
    STA btlmag_effect                   ; and flow into casting on player   

The purpose of this is to make a Drain effect. Suck a certain amount of HP from the enemy, then heal for either that exact amount, or the amount of HP remaining on the enemy before they die. Saving bytes is crucial in this particular instance. Is there anything I can do to save even 1 byte? And do I even have my math logic right?

Version 2: one that actually works (Version 1 saves 3 bytes by jumping back, but that one ends in a JMP instead of a JSR, so it never heals.)

Code: [Select]
    ;JSR Battle_CastMagicOnEnemy

    JSR BtlMag_LoadEnemyDefenderStats   ; load enemy stats into defender mem
    LDX #MATHBUF_MAGDEFENDERHP          ; backup the enemy's current HP
    LDY #MATHBUF_AILMENTCHANCE          ; and save it as "ailment chance" which shouldn't be used by damage spells
    JSR MathBuf_CopyXToY
    JSR BtlMag_PerformSpellEffect       ; do the spell (modifying defender's stats)
    JSR BtlMag_SaveEnemyDefenderStats   ; update changed enemy stats.
   
    LDX btl_defender
    JSR DoesEnemyXExist
    BNE :+
   
    LDA math_ailmentchance              ; if damage is greater than HP (enemy died from it!) take their HP
    STA math_basedamage                 ; and save as the max damage to heal; only one byte since healing caps at 255
   
  : JSR TargetSelf                      ; now target the caster
   
;    LDX #MATHBUF_AILMENTCHANCE          ; compare enemy's HP pre-damage
;    LDY #MATHBUF_BASEDAMAGE             ; to the amount of damage done
;    JSR MathBuf_Compare
;      BCC :+                            ; C = set if Y >= X, clear if Y < X
   
;    LDA math_ailmentchance              ; if damage is greater than HP, take their HP
;    STA math_basedamage                 ; and save as the max damage to heal; only one byte since healing caps at 255

;  :
    LDA #$13                            ; now load up the effect for Drain healing
    STA btlmag_effect                   ; and flow into casting on player   
« Last Edit: July 25, 2019, 02:03:35 am by Jiggers »
I know exactly what I'm doing. I just don't know what effect it's going to have.