(Link to AcmlmWiki) Offline: thank ||bass
Register | Login
Views: 13,040,846
Main | Memberlist | Active users | Calendar | Chat | Online users
Ranks | FAQ | ACS | Stats | Color Chart | Search | Photo album
04-27-24 08:18 AM
0 users currently in ROM Hacking.
Acmlm's Board - I3 Archive - ROM Hacking - Hacking "walk through walls"? New poll | |
Add to favorites | Next newer thread | Next older thread
User Post
Stabwound

Goomba








Since: 05-11-06

Last post: 6386 days
Last view: 6386 days
Posted on 10-31-06 05:28 PM Link | Quote
I am pretty good at figuring out how to accomplish most things, but I am a bit stumped when it comes to this.

Is there a general method that could be used to hack a "walk through walls" code? In one game a while ago, I found that it was as simple as a flag that gets set in RAM to determine whether or not you could pass through the left/right/up/down, but that doesn't seem to work in most games I've tried.

How are boundries set up in most NES/SNES games? Are there just hardcoded tiles that say "can't pass"?
Kailieann



 





Since: 11-18-05

Last post: 6277 days
Last view: 6277 days
Posted on 10-31-06 07:35 PM Link | Quote
Theoretically most games would have a global (or at least semi-global) subroutine to check whether or not a tile is passable, regardless of what system the game uses to define passable objects.

Bypassing or altering such a routine would be easy enough. The hard part would be actually finding it.
Stabwound

Goomba








Since: 05-11-06

Last post: 6386 days
Last view: 6386 days
Posted on 10-31-06 08:24 PM Link | Quote
Originally posted by Kailieann
Theoretically most games would have a global (or at least semi-global) subroutine to check whether or not a tile is passable, regardless of what system the game uses to define passable objects.

Bypassing or altering such a routine would be easy enough. The hard part would be actually finding it.

Yeah, that's what I figured. I was just hoping there was a workable method to find the routine. It's not too hard to find most routines related to the player character but I have no idea how to go about finding the routine that would determine whether you can pass through the wall or not.
Moppy

Red Goomba








Since: 09-26-06
From: Rochester, NY

Last post: 6296 days
Last view: 6280 days
Posted on 10-31-06 08:45 PM Link | Quote
Finding the memory location of the player's x/y would probably be a good place to start. Look for a routine that writes to it every frame that you move, and somewhere before that, there is likely to be code that could potentially jump over that routine based on the collision conditions. It will probably be accompanied by a read from a ROM address, since it's looking up a value in a static table.

With something like Geiger's Snes9x debugger, log a few frames of movement, find where the code writes to your position, and seek back a bit. Try running into a wall to see how the code sequence changes.

Hope this helps?
never-obsolete

Paragoomba








Since: 05-14-06
From: AZ

Last post: 6279 days
Last view: 6279 days
Posted on 10-31-06 10:20 PM Link | Quote
here's the routine i used to check collision between two "objects" in a mario bros. clone. if the game uses metatiles, you might find something similar where a lot of ram values are being compared.

this routine assumes the screen (0,0) is in top left corner



;-----------------------SubCheckCollision-----------------------
;
;    Description:    Check collision between two different
;        objects.
;
;    Arguments:    Obj1X, Obj1Y, Obj1W, Obj1H
;        Obj2X, Obj2Y, Obj2W, Obj2H
;
;    Return:    0(F) or 1(T) pushed on stack

SubCheckCollision:
    pla    ; preserve the return PC
    tax
    pla
    tay

    ; if(Object2Right < Object1Left) then jump to exit on fail
    lda Obj2X        ;     R L
    clc              ; +---+ +---+
    adc Obj2W        ; | 2 | | 1 |
    cmp Obj1X        ; +---+ +---+
    bcc SetCollisionFail    ; Note: object2 is left of object1

    ; if(Object1Right < Object2Left) then jump to exit on fail
    lda Obj1X        ;     R L
    clc              ; +---+ +---+
    adc Obj1W        ; | 1 | | 2 |
    cmp Obj2X        ; +---+ +---+
    bcc SetCollisionFail    ; Note: object2 is right of object1

    ; if(Object2Bottom < Object1Top) then jump to exit on fail
    lda Obj2Y        ;  | 2 |
    clc              ; B+---+
    adc Obj2H        ; T+---+
    cmp Obj1Y        ;  | 1 |
    bcc SetCollisionFail    ; Note: object2 is above object1

    ; if(Object1Bottom < Object2Top) then jump to exit on fail
    lda Obj1Y        ;  | 1 |
    clc              ; B+---+
    adc Obj1H        ; T+---+
    cmp Obj2Y        ;  | 2 |
    bcc SetCollisionFail    ; Note: object2 is below object1

SetCollisionPass:
    lda #01    ; push a 1(T) on the stack
    pha
    jmp ExitCheckCollision

SetCollisionFail:
    lda #00    ; push a 0(F) on the stack
    pha

ExitCheckCollision:
    tya    ; push the return PC back on the stack
    pha
    txa
    pha
    rts

HyperHacker

Star Mario
Finally being paid to code in VB! If only I still enjoyed that. <_<
Wii #7182 6487 4198 1828


 





Since: 11-18-05
From: Canada, w00t!
My computer's specs, if anyone gives a damn.
STOP TRUNCATING THIS >8^(

Last post: 6278 days
Last view: 6278 days
Posted on 11-01-06 02:12 AM Link | Quote
It really depends on the type of game. In a top-down 2D game like Pokémon or older Zeldas, you might just have flags in RAM telling which directions you can move in or bytes specifying what type of tiles surround you (which the game would use in a lookup table to see what happens when you try to walk into them). 2D platformers like Super Mario Bros tend to be similar; the same basic "player overtop of a tilemap" system, but with physics and graphics that give a side view feel rather than a top view. However, because of the generally faster pace of these games, many (such as Super Mario World) instead have a piece of code that each tile runs when you touch it; the solid ones would simply push you back out (if you ever get stuck inside a solid wall in these games, you tend to just slide left or right). In this case you'd want to hack the routine responsible for calling this code to always call the code of one specific tile.

3D hit detection is a huge pain, so I have no experience hacking it.
Surlent

Koopa
Back to the roots








Since: 11-18-05
From: Berlin, Germany

Last post: 6289 days
Last view: 6289 days
Posted on 11-01-06 04:08 AM Link | Quote
Originally posted by HyperHacker
[...]However, because of the generally faster pace of these games, many (such as Super Mario World) instead have a piece of code that each tile runs when you touch it; the solid ones would simply push you back out (if you ever get stuck inside a solid wall in these games, you tend to just slide left or right). In this case you'd want to hack the routine responsible for calling this code to always call the code of one specific tile [...]

Reminds me about Block Tool, which contains arrow blocks as well (passable from three sides only; but usually you put something solid to their sides, so it's a true one-way-block then).
I am interested in collision detection as well, but although I have no clue of assembly nor advanced hex editing, I have a question:

If every game used the same location and similar code, it actually would be very easy to figure this out. In RPG maker each tile simply has a flag, "passable or not passable". If you are in front of such a solid obstable, then the arrow key simply is bypassed in that direction.

My theory might be, that the editor checks the movement inputs first; if there is NO obstacle in the location the sprite is intented to move, the move command will be executed. If it's not there, it's simply ignored. That also might explain the lack of the movement animation if you try to move further, when you are touching a wall.

Okay, I don't want to go too off topic; but which method is more efficient for sprite/collision detection ?

A) Flagging all objects passable or impassable, then "pushing" the character back (maybe before the frame is drawn on screen - otherwise it might be a very ugly result). So this is basically HyperHacker's explanation.

B) Intercepting the movement inputs before the command is executed; something like

IF solidness(destination tile+1)="1" THEN { GOTO Thou shall not pass}

(meaning 0 = passable and 1 = solid, of course) ?
HyperHacker

Star Mario
Finally being paid to code in VB! If only I still enjoyed that. <_<
Wii #7182 6487 4198 1828


 





Since: 11-18-05
From: Canada, w00t!
My computer's specs, if anyone gives a damn.
STOP TRUNCATING THIS >8^(

Last post: 6278 days
Last view: 6278 days
Posted on 11-02-06 03:10 AM Link | Quote
Really, A is best for platformers while B is best for RPGs. Consider in an RPG, you move one tile each time the direction key is held (or something such as a specific floor tile is simulating it) and you aren't in the middle of your moving animation. It's trivial to just tweak the movement routine to abort if the tile in that direction is impassable.
On the other hand, in a platformer you're generally moving around with some actual physics; gravity, acceleration and deceleration, etc. You can't just disable the direction keys when an impassable tile is in front of the player because they may be moving without holding the keys (eg by falling or getting a running start). The easiest way here is to just check if the player is inside an impassible tile and if so move them back out the way they came at the same speed they're moving or more. Since you'd do the check and movement before drawing, the character is only within the wall for a few CPU cycles.
Of course this method does have one flaw in that you can move so fast you fly right through a wall, never triggering the "player in impassable tile" routine because you skipped the tile entirely. Games have different ways of avoiding this; some (particularly 3D games) use raycasting to determine whether the player's path intersects a wall, others move the player one pixel at a time, checking their position after each movement, until they reach the destination spot each frame; and some (I think Super Mario World is one of these) just make the characters slow enough and the walls thick enough that this hopefully will never happen.
Dwedit

Rope
フクト オン フォニクス








Since: 11-17-05
From: Chicago!

Last post: 6279 days
Last view: 6278 days
Posted on 11-02-06 05:09 AM Link | Quote
ASM Hacking games to walk through walls is really easy. I just did it for Dragon Warrior 1: 31EA: 0E -> FF.
Stabwound

Goomba








Since: 05-11-06

Last post: 6386 days
Last view: 6386 days
Posted on 11-02-06 05:24 AM Link | Quote
Well... I guess I'll look at that DW routine then.

Thanks to everyone for the input. I haven't really messed with it much since I posted this thread but I will soon.
Dwedit

Rope
フクト オン フォニクス








Since: 11-17-05
From: Chicago!

Last post: 6279 days
Last view: 6278 days
Posted on 11-02-06 06:49 AM Link | Quote
For dragon warrior 3, it's 00035892: 38->18
DW3 stores a set of flags for each tile. If bit 80 is on, the tile is a wall.
This asm hack changes the code to it jumps to when its a wall to instead tell the game to use the carry flag it would normally use when its not a wall.
I couldn't find the equivalent hack for the overworld though.

DW1 on the other hand just says that any tile past 0E is a wall, so changing CMP #0E to CMP #FF is enough for walk-thru-walls in that game.


(edited by Dwedit on 11-02-06 05:50 AM)
Kejardon

Shyguy








Since: 05-21-06

Last post: 6278 days
Last view: 6277 days
Posted on 11-02-06 01:01 PM Link | Quote
I'd think B would be more common regardless:
Calculate the would-be new position to see if it collides with any solid objects, if so, align the character with the border instead of inside the solid object (and idealy repeat the check for the new position)

Of course, it can vary drastically depending on the game, I guess. But B makes more sense to me, personally.

But the best way to find collision detection would first be to find the current position (and speed if it's an action game) in ram, then trace the game when you collide with something and use the ram offsets to look for the relevant code. In my opinion.
Zepper

Paragoomba








Since: 09-04-06
From: Brazil

Last post: 6278 days
Last view: 6277 days
Posted on 11-03-06 05:22 PM Link | Quote
Yes, the idea is to trap different reads, as zero/non-zero, to spot the asm code. However, it's not for any game, as Rockman (NES) seems limited to TSA types: if you fake the value, the floor might disappear, or the spikes might become "air", and so on. The coolest games that I could play with this hacking were DukeNuken3D and Wheel of Time (PC) and Metroid Zero Mission (GBA), awesome.
Mega-Dog



 





Since: 11-19-05
From: Minnesota

Last post: 6299 days
Last view: 6280 days
Posted on 11-07-06 10:34 AM Link | Quote
From my experience it depends on the game. I have noticed when hacking with alot of games it is just a matter of finding the hard core TSA and switching it...some can be code routine switches. I have only found a few but I know in atleast 50+ games you can do it by switching TSA properties.

It is possible that the Dragon Wariror ones might just work for 1 pattern table since I know in Karnov that if you give the TSA tile a certain property it determines if it is solid or not. Same with Metroid and a few others.
Dwedit

Rope
フクト オン フォニクス








Since: 11-17-05
From: Chicago!

Last post: 6279 days
Last view: 6278 days
Posted on 11-07-06 11:12 AM Link | Quote
Looks like I'll actually have to explain how my hacks worked...

Okay, here's DW1:

Whenever you attempt to enter a tile, or leave a tile, DW1 checks if the tile is walkable or not. From the beginning:
DW1 stores its maps in a nibble-packed format, each 4 bits is a tile. Most significant 4 bits are the left tile. If you want to know where the maps are located, use Townedit.
DW1 reads the tile number, but this is not the real tile number, there are three different sets of tile numbers to choose from. There's one for Towns (located at 1A10-1A1F), one for caves (located at 1A20-1A27), and one for the overworld (located at 19F3-1A0F). From there, you have the real, honest-to-god, tile number.
Then the game checks if the tile number is 0x17, if so, it checks if the princess has been rescued or not, if so, the tile is replaced with 0x04. Yes it does this for every tile it renders or you collide with.

And here's the list of tile numbers:
00-Grass
01-Sand
02-Mound
03-Stairs Up
04-Floor
05-Stairs Dn
06-Swamp
07-Town
08-Cave
09-Castle
0A-Bridge
0B-Forest
0C-Chest
0D-Barrier
0E-Desk
0F-Water
10-Stone Block
11-Locked Door
12-Craggy Mnts
13-Weapon Shop
14-Inn
15-Roof
16-Black Tile
17-Princess
18-26:Shoreline

You'll notice that all before 0E are passable, and all afterward are walls.
DW1 does not store flags for tiles at all. It just uses the tile number for everything.
And here's the code which checks for if it's a wall or not:

$B1D7:A5 3C     LDA $3C = #$04
$B1D9:C9 0E     CMP #$0E
$B1DB:90 18     BCC $B1F5


And it's no coincidence that all tiles 0E and beyond are impassable.

Here's DW3:

After decompression, DW3 stores its maps starting at 0x7400 (this is in SRAM!). It also stores a table with tile attributes at 6DE0-6DFF. There is no consistency between tile numbers this time around, they are always different for every map, the only thing for sure is that there is a maximum of 32 different tiles, and the remaining 3 high bits are used to indicate which room a tile is in.
There is code at 9878 which reads which tile you are trying to step on, then reads from the tile flags table. If the tile's most significant bit (the wall bit) is set, the tile is a wall.

$9874:18        CLC
$9875:60        RTS
$9876:38        SEC
$9877:60        RTS
$9878:A5 7C     LDA $7C = #$1D
$987A:29 1F     AND #$1F
$987C:AA        TAX
$987D:BD E0 6D  LDA $6DE0,X @ $6DFD = #$00
$9880:10 F2     BPL $9874
$9882:38        SEC
$9883:60        RTS


By changing the CLC instruction at 9874 to SEC, the game would return the same carry flag for both walls and nonwalls, so you would walk through walls.
I haven't figured out how the overworld works however. The overworld also builds the tile flags table at 6DE0-6DFF, but never actually reads from there to determine passability.


(edited by Dwedit on 11-07-06 10:28 AM)
(edited by Dwedit on 11-07-06 10:29 AM)
Add to favorites | Next newer thread | Next older thread
Acmlm's Board - I3 Archive - ROM Hacking - Hacking "walk through walls"? |


ABII

Acmlmboard 1.92.999, 9/17/2006
©2000-2006 Acmlm, Emuz, Blades, Xkeeper

Page rendered in 0.018 seconds; used 437.55 kB (max 554.33 kB)