Basic Questions and Answers Thread

Discussion in 'Discussion & Q&A' started by Malevolence, Jul 7, 2009.

  1. Devon

    Devon Down you're going... down you're going... Member

    Joined:
    Aug 26, 2013
    Messages:
    1,372
    Location:
    your mom
    To work around that, you would have to check if Knuckles is gliding, and if he is, then branch to skip that code.

    EDIT: Nevermind
     
    Last edited by a moderator: Apr 11, 2015
  2. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    922
    Won't that cause the object to break whenever Knuckles glides, even if he's not touching it? Also he said he wanted it to break when jumping, not just gliding.

    Edit: looking at the code I added in Sonic 2 Adventure Edition so that Sonic could break breakable blocks from the side with a homing attack, after the call to SolidObject, bit 16 of d6 is set if player 1 is touching the object's side.

    So change #5,status(a0) to #16,d6 and it should work.
     
    Last edited by a moderator: Apr 11, 2015
  3. Devon

    Devon Down you're going... down you're going... Member

    Joined:
    Aug 26, 2013
    Messages:
    1,372
    Location:
    your mom
    EDIT: Trash
     
    Last edited by a moderator: Apr 11, 2015
  4. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    I have a bug in Sonic 128 Hivebrain where Sonic and objects will act like they're in the air when they're standing on an object. This leads to Sonic's animations getting screwed up and only using one frame and monitors falling through when Sonic comes in contact with it. Does anyone have a solution to this?

    I know I've already asked this question but I barely got an answer and since then, I've searched through and compared my disassembly to a clean one I've found nothing.
     
  5. ShadowOne

    ShadowOne Newcomer Member

    Joined:
    Jul 28, 2014
    Messages:
    23
    I will post my question here since

    1) I don't want to create a thread just for one silly question (And I'll be warning-free this way xD)
    2) I don't know where else to ask since I know some of you know ASM and are quite skilled at it.

    So here's the deal:

    I want to create something similar to an IF statement with ASM code for my hack.

    Let's say the logic would be something like this:

    If (button X input)

       Set Status to Fast

    else

       Set status to default.

    • 009840-009840 (000001) = Status (00 = Normal, 01 = Burnt, 03 = Skip Sandwich)
    ^That's RAM data.

    Basically that's the thing.
    This is being done in a SNES ROM, though.

    So I want the game to question if the Button Y is being pressed, if it is, then it should set the Status of the Character to "Skip Sandwich" (which is the equivalent to running in-game), if the button is not pressed, then it should go back to the Normal or Burnt state depending on what is the state if the Button Y is not pressed, so when the game requests the burnt sprite for the character it shows up proerly.

    The main problem right now with the Run patch that exists for that game is that the Burnt Status gets overwritten by the Skip Sandwich status, whenever the character tries to do a teleportation in the game and fails, the sprite quickly shifts to a walking animation for the character, and that's what I want to avoid with the code...

    To make it request the Skip Sandwich status ONLY when the button is being pressed, otherwise it should be whatever other status it has.

    Hope I made myself clear on my idea.

    Any suggestions as to how to do this with ASM code?

    Additional info that might help:

    http://datacrystal.romhacking.net/wiki/EarthBound:ROM_map

    http://datacrystal.romhacking.net/wiki/EarthBound:RAM_map

    I don't know yet how the button inputs are registered/read for SNES games.
     
    Last edited by a moderator: Apr 13, 2015
  6. Pacca

    Pacca Having an online identity crisis since 2019 Member

    Joined:
    Jul 5, 2014
    Messages:
    1,175
    Location:
    Limbo
    After looking the subject over for a bit, it seems the SNES does things in a very similar fashion to the Genesis. The "If" statement for a Genesis/SNES game has to be carried out by two lines; one "CMP" command, which runs the logic statement, and a specialized branch command to move to different code then that below if and only if the above "cmp" command is true. Googling for basic SNES ASM tutorials brought me to this. I'd look over the whole thing if I were you, but the part which pertains to you is under "Lesson 3: Branching and Conditions". Hope this helps.

    P.S. If your worried by the fact that the guide references mario, that is just as an example; it's completely irrelevant at the level of assembly coding.
     
  7. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    While I can't exactly be a massive help because I know jack shit about Earthbound and the SNES, doesn't the 65816 use CMP/BIT for its conditional tests and BNE/BEQ for its conditional branches, which work similar to the 68000?

    Also, when looking around for controllers, I found this. So I'd imagine it'd probably look something like this (example only! I'm not entirely sure!):

    Code:
     LDA               $4016              ; Load joypad's value to accumulator.
     BIT                #$40                ; Is X being pressed?
     BEQ             Label                ; If not, branch.
     LDA             #$03                 ; Set to Skip Sandwich
     STA              $009840          ; Set as status.
     
    Label:
     
     *Continue with code*
    
    EDIT: Ninja'd.
     
    Last edited by a moderator: Apr 13, 2015
  8. ShadowOne

    ShadowOne Newcomer Member

    Joined:
    Jul 28, 2014
    Messages:
    23
    Thank you both, Pacguy and Dandaman955, for your answers.

    Pacguy:

    OK so we have:

    *009840-009840 (000001) = Status (00 = Normal, 01 = Burnt, 03 = Skip Sandwich)

    According to Dandaman's info and my assumption, button Y should be $4000, and LDA $009840 should be the RAM address that I should load. Then:


     LDA             $4016              ; Load joypad's value to accumulator.
    CMP #$4000             ; Is Button Y being pressed?
     BEQ             RunButton          ; Branch to RunButton label.
    RTS ; Return if Button Y is not being pressed. End code.

    RunButton: ; If Button Y is being pressed, load the following code.
     LDA             #$03               ; Set to Skip Sandwich status
     STA             $009840          ; Set as status.
    RTS ; Return after code has been executed.

    What do you think of that code? Would it work in theory?

    I want to know also if the change of status specified in the RunButton label would apply only when I press the button, or if the change will be permanent in RAM with just one button press.

    One last thing... If the code I posted was right, how can I implement something like this if I want to add another comparison for let's say the Burnt Status, since the current Run patch screws up that sprite due to the 01-04 HEX values in that address. So I want to make it say something like:


    LDA $009840          ; Load RAM Address for Character Status.
    CMP #$01             ; Is Burnt Status being loaded?
    (If yes then)
    RTS ; Return if Burnt Sprite is being loaded AND avoid entering RunButton code.

    Dandaman955:

    So basically LDA $4016 loads what would be the controller in Port 1 (Data1) to the accumulator, right?

    The question is, how can I know what HEX value corresponds to what button?

    The JoyPad data shows the following:

    "byetUDLRaxlr0000"

    Having the button I require (Y) into the 15 position (or 14 bit if you count the first one as 0), and I separate accordingly in bits for HEX conversion:

    byet  UDLR axlr   0000

    0100 0000  0000 0000 => $4000 (Button Y)

    0000 0000  0100 0000 => $0040 (Button X)

    Is that correct? If I want to specify that i want the code to read from Button Y it should be like this:

    BIT $4000

    Please, correct me if I am wrong.

    Also, what would happen with the 'BEQ Label' part of the code if I don't have any more code besides my particular IF statement?
    The Tool I am using simply grabs whatever ASM I write into a CSS file and then compiles the ROM back, but I don't need to have the whole ROM in ASM for it to work. The additional code or values are being put into an expanded area in the ROM.

    Thank you so much guys for your help!
     
    Last edited by a moderator: Apr 13, 2015
  9. presto

    presto Raised from the dead... Member

    Joined:
    Oct 12, 2014
    Messages:
    40
    Location:
    Cluj-Napoca
    I know this is a really nooby question, but what is the flag for Sonic's animation "slot",the one that isn't $1C(a0)? (In Sonic 1)
     
    Last edited by a moderator: Apr 13, 2015
  10. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    After looking at this again, I may have goofed on how BIT instructions are used. If it works anything like the btst instruction works on the 68000, then BIT #$40 for example may have to be written as  BIT #6 and BIT #$4000 may have to be changed to BIT #14 or something, instead. It isn't documented particularly well. Other than that, I'd imagine it should work, yes.

    If I understand correctly, an RTS will do.
     
  11. Pacca

    Pacca Having an online identity crisis since 2019 Member

    Joined:
    Jul 5, 2014
    Messages:
    1,175
    Location:
    Limbo
    What is the maximum limit for rings in a level? The last time I accidentally went over the limit, I nearly restarted my hack until I found out, and then deleted over 40 rings to make it match the original levels ring count (which was painful, and makes some areas feel more empty then they should).

    EDIT: This is in Sonic 2.
     
    Last edited by a moderator: Apr 14, 2015
  12. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    922
    The most Sonic 2 can have in a level normally is 256 rings. You can increase the limit by increasing the size of the RAM area reserved for rings (Ring_Positions, six bytes per ring), or by porting the S3K ring manager, which stores individual rings instead of ring groups, and gives you three times as many rings using the same RAM space.
     
  13. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    I ported Sonic CD's spring object to Sonic 128 Hivebrain disassembly but in the odd numbered levels (LZ, SYZ, SBZ), the springs will have no affect on the player (Sonic won't collide with or get pushed by the springs) despite there being no use of the RAM location for zones ($FFFFFE10) in the code I ported.

    Edit: The disassembly I used
     
    Last edited by a moderator: Apr 18, 2015
  14. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    Sorry to double post but I solved the problem when working on a different problem. If you're trying this yourself, remember to delete or comment out in sub_207B0C:


    tst.b ($FF1906).l
    bne.w loc_207DC0

    As long as I'm posting, I guess I'll say the problem I currently have:

    When I hit a vertical spring (the one where you gain speed, not height) it disappears. I assume this was supposed to be used for the springs that popped out of the ground but since I don't have that in Sonic 1, it always uses it.

    Edit: I just played the remake Sonic CD and the springs the pop out of the ground don't work like I thought it did, leaving me with no idea why this is happening.
     
    Last edited by a moderator: Apr 19, 2015
  15. tilk

    tilk Active Member Member

    Joined:
    Feb 2, 2012
    Messages:
    30
    So..! this might sound as a silly question, but here I go anyways..! In the ReadySonic Disassembly, there's an option to load chunks from ROM, and after some inspection I found that it uses code like this:


    move.l #Blk256_GHZ,(v_256x256).l ; store the ROM address for the chunk mappings

    how does this work? to me, it seems that actually the freed Ram doesn't starts at $F00000 And if I'm correct, where it starts? this and how the btst command works are 2 things that confuses me... (The later because I don't know what it is exactly testing... if used with a beq.s, if 1 branches and 0 continues with the rest of the code..?)

    Thanks for Reading!
     
  16. Pacca

    Pacca Having an online identity crisis since 2019 Member

    Joined:
    Jul 5, 2014
    Messages:
    1,175
    Location:
    Limbo
    The way that the genesis reads things is a little weird. The Rom data (all the game code, art, and in this case, the level chunks), are read from address $0 to wherever the end of the rom lies. However, actual RAM starts at $FFFF0000, thus reading from any thing below $FFFF0000 should get you to read from rom (with some possible other reserved exceptions in between, like vram and sram). Anyone, feel free to correct me if I'm wrong, this is all based on experience.
     
  17. MarkeyJester

    MarkeyJester ♡ ! Member

    Joined:
    Jun 27, 2009
    Messages:
    2,867
    The Memory Map consists of:

    000000 - 3FFFFF = ROM cartridge hardware space

    400000 - 7FFFFF = Mega CD hardware space

    800000 - 9FFFFF = 32x hardware space

    A00000 - A0FFFF = Z80 RAM space

    A10000 - A10FFF = System I/O

    A11000 - AFFFFF = Hardware control (TMSS/Z80 Bus/Memory mode/etc)

    B00000 - BFFFFF = Said to be reserved (clarification needed)

    C00000 - DFFFFF = VDP space

    E00000 - FFFFFF = 68k RAM space

    There are minor alterations to the map based on additional hardware or alterations to the cartridge itself. But what's there above is the standard map you would expect to use.

    Now, a lot of the access range is mirrored. That is to say E00000 - E0FFFF is 68k RAM 0000 - FFFF. But so is E10000 - E1FFFF, and so is E20000 - E2FFFF. The 68k RAM space is mirrored throughout E00000 - FFFFFF. A lot of games use the range from FF0000 - FFFFFF simply to take advantage of the 68k's automatic sign extension, and 24-bit BUS.

    If you were to access FFFF8000, the most significant byte is ignored by the BUS, automatically making it FF8000. But by assembling ($FFFF8000).w, the assembler will save only the 8000 into the instruction, the FFFF is omitted. The 68k will load the 8000 from the instruction, and automatically sign extend it into long-word. Values from 8000 - FFFF will extend to FFFF8000 - FFFFFFFF, values from 0000 - 7FFF will extend to 00000000 - 00007FFF:

    8000 -> FFFF8000 -> 00FF8000 -> RAM 8000.

    Storing/loading/accessing addresses through a sign extended 8000 is quicker and smaller than accessing 00FF8000 as a long-word unsigned.
     
  18. tilk

    tilk Active Member Member

    Joined:
    Feb 2, 2012
    Messages:
    30
    Oh... I see. Thank you guys! Specially you Markey. now I can be sure about how it works... (Now that I think so, I'll copy that to a .txt Document.)
     
  19. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    Here's a question I have that I'm sure some knows the answer to:

    In my Original Sonic 128 (Hivebrain) disassembly hack, I ported levels from other Sonic games. Because of this I have the collision data from Sonic 2 and Sonic 3K and I need to make the game load certain collision for each level. I originally got away with making checks for certain levels but once I added my third ported level, I wanted to make it simpler.

    Here's what I tried for some code that loads the primary collision array:


    loc_14A22:
    andi.w #$F,d1 ; MJ: get only within 10 (d1 is pixel based on the collision block)
    add.w d0,d1 ; MJ: add collision ID (x10) (d0 is the collision block being read)
    moveq #0,d3
    move.b ($FFFFFE10).w,d3
    lea CollArrayTable(pc,d3.w),a2 ; MJ: load Sonic 3K's collision array data to a2
    move.b (a2,d1.w),d0 ; MJ: load solid value
    ext.w d0 ; MJ: clear left byte
    eor.w d6,d4 ; MJ: set ceiling/wall bits
    btst #$B,d4 ; MJ: is sonic walking on the left wall?
    beq.s loc_14A3E ; MJ: if not, branch
    neg.w d0 ; MJ: reverse solid value

    At the end of the subroutine:


    CollArrayTable:
            dc.l    CollArray21    ; GHZ
            dc.l    CollArray2    ; LZ
            dc.l    CollArray1    ; MZ
            dc.l    CollArray3K1    ; SLZ
            dc.l    CollArray1    ; SYZ
            dc.l    CollArray21    ; SBZ
            dc.l    CollArray21    ; END

    When try this, the collision doesn't load correctly and I can't figure out the problem.
     
  20. Pacca

    Pacca Having an online identity crisis since 2019 Member

    Joined:
    Jul 5, 2014
    Messages:
    1,175
    Location:
    Limbo
    I did this in sonic 2 by replacing all the parts where it asks for collision with a jsr to a subroutine which checks which level it is, then switches accordingly. I'll add more when I'm back at my computer.

    EDIT: I assume you also have S3Ks angles files setup?
     
    Last edited by a moderator: Apr 20, 2015