Banner
Views: 236,437,476
Time: 2013-05-23 03:48:38 PM
27 users online: o 1UPdudes, o AnybodyAgrees, blue leader, buggy789, Dylancd5010, EvilGuy0613, gerg357, Grav, o grishnax, HyperMario, Koopster, o Ladida, MaskOTerror, MolSno, nickofzo, NovaSquirrel, phenolatukas, Ramidalv, Rockythetigre, o S.N.N., ShadowFan-X, Shog, Sokobansolver, Vitor Vilela, Yasuo, Z0mbie1337, o Zildjian - Guests: 33 - Bots: 6Users: 22,871 (1,276 active)
Latest: julian2908
Tip: Bad things to do in the title demo: Enter a door or a pipe, activate a P-switch or a star, complete the level, hit a message block, or die. These will either glitch the music, or force the player into an endlessly looping title level until they reset the game.
Kipernal's Guide for Beginners to HDMA
Forum Index - SMW Hacking - General SMW Hacking Help - Tutorials - Kipernal's Guide for Beginners to HDMA
Pages: « 1 »

Kipernal's Guide for Beginners to HDMA!



Hello there, and welcome to the KGB-- ...um...hold on.



Kipernal's Beginner Guide to HDMA!



Hello there, and now that we've gotten one unfunny joke out of the way, welcome to KBGHDMA. This guide will take you though the very basics of HDMA. By the time I'm finished with you you should be able to program simple color gradients without having to rely on fake HDMA, and you'll be ready to read up on the more advanced stuff presented in Kaijyuu's HDMA tutorial. Why am I making this tutorial if Kaijyuu already made one, you ask? Because, with all respect to him, I found certain parts of Kaijyuu's tutorial a bit difficult to understand at first, and so I'm making this tutorial so you people who share my intellectual constipation can grasp the basics of HDMA. I'll try to explain everything as best I can, but before we go on you MUST understand the following concepts in ASM:

-How to use it (this is not an ASM tutorial, nor will it ever be. I will explain certain things when I feel it may be required, however)

-Indexing (and, by extension, what a table is)

-How to understand numbers in binary

And...that's about it. One final note before we begin, however. I do not want you to simply memorize "okay, so I LDA some number and STA it here for some reason and I get a pretty rainbow." No. That won't do. It is one thing to know something, and it is something completely different to understand it. I want you to know why you load that specific number and why you store it to that specific address. You should be able to predict, with reasonable accuracy, what would happen if you loaded some different number or stored it to some different address. When you're done you should never want to see this guide again because it's so full of stuff that you already understand! Okay? Are we clear? Then without further ado, let's go learn you some HDMA!




Lesson 1: Registers



...yeah, okay, I lied. We need to cover this first, since it will lay the foundation of what you need to know. The SNES has various addresses you can write to, called "registers." These registers will cause different effects to occur depending on what you write and where you write it. For example, if I wrote #$07 to the register $2100, it would dim the screen to half brightness. $2100 is the brightness register, so writing to it will, logically, change the brightness of the screen. For the purpose of HDMA you can use any register between $2100 and $21FF, and some important ones you may find useful are listed here:

$2100: Screen brightness.
$210D: Layer 1 horizontal position
$210E: Layer 1 vertical position
$210F: Layer 2 horizontal position
$2110: Layer 2 vertical position
$2111: Layer 3 horizontal position
$2112: Layer 3 vertical position
$2132: Background color (it's more complicated than just that, but for now this is what we'll call it)

So writing to $2100 will change the brightness. Writing to $210D will change the horizontal position of layer 1. If you'd like to know what every register does, check out regs.txt by Anomie. It contains a description of every single standard SNES register, and, while it is a bit technical, should tell you everything you could want to know.

Now here's the catch: you can't just go setting $2100, the brightness register, to whatever value you want at any time you want. It won't work. You see, most of these registers can only be written to during a blank. What is a blank? It's a bit complicated, so I'll go ahead and give it its own mini-section.

Lesson 1-and-a-little-bit: Blanks



Okay, let's assume that you're playing your SNES on an old CRT television (hopefully you know what those are...I'm going to feel really old if you don't). In order to draw the screen, an electron gun is fired at the screen and draws the scene pixel by pixel horizontally from left to right, top to bottom. Once it finishes with one whole row, called a "scanline," the gun turns off, moves down one row, back to the left side of the screen, turns on, and repeats the process. Once it finishes drawing the entire screen, the gun turns off, moves up all the way back to the starting position, and begins again. This, of course, happens in a fraction of a second (1/60th of a second, to be exact).

Now, that's all well and good, but I still haven't explained blanking, have I? "Blanking" is the term given to the period of time in which the electron gun is turned off and moving to a different point of the screen. The blank that occurs after the gun as drawn one row of pixels is called "H-Blank," and the blank after it draws the whole screen is "V-Blank." If you'd like a visual representation:



Alright, so how does that tie into registers? Well, most of the registers that we care about for HDMA can only be written to during a blank. And given that, for the intents and purposes of what we're doing, we can not get code to run during a blank, how are we going to change these registers?

Lesson 2: HDMA



Okay, now I'll talk about what HDMA is. HDMA stands for Horizontal Direct Memory Access, but you don't need to know what that means. Essentially, using HDMA we'll be able to write to these registers at various blanks without having to waste CPU cycles on code and stuff. Here's what HDMA does, in a nutshell: It sets a register to various values; the value it sets is dependent on the vertical position of the screen.

Let's look at a practical example. Let's say I want the top half of the screen to be bright and the bottom to be dark. To do this I'd want to set $2100 to #$0F on the first scanline, then, maybe 100 scanlines down, I'd set $2100 to #$03. HDMA allows us to accomplish this very easily. In fact, I could set a different value to $2100 on every single scanline if I wanted to.

Okay, we're done with the conceptual stuff. Before you go on, make 100% sure that you understand every single concept I just went over. I'm not kidding. You're not going to be able to get what's going on next if you don't understand every last concept in the first two sections.

No, really. Go re-read the beginning again. Copy it down in a notebook or something. Make sure you really, really understand what's going on, or all this stuff coming up will be nonsense.

Lesson 3: The Setup



Now I'm going to show you how to set up this fancy-schmancy HDMA thingamajig. In order to use HDMA, you have to set some registers specifically designed for HDMA and DMA. There registers you need to know for this are as follows: (Note that the x signifies the DMA "channel" to use; I'll explain a bit later. Just note for now that you replace "x" with a number from 0 to 7).

  • 43x0: This contains some complicated stuff, but the most important to us are the last three bits, which set the transfer mode. To start off, though, always just set this to #$00.
  • 43x1: This is the register you want to write to. If you wanted to use HDMA to change the layer 1 X position, for example, you'd write #$0D to this register.
  • 43x2:
    43x3:
    43x4: These three addresses should point to your HDMA table. I'll explain in greater detail later, but know that the table is where the "data" for your effects are stored. x2 is the low byte, x3 is the high byte, and x4 is the bank byte. Again, if this is confusing, it will make more sense once we actually start writing the code.


Alright, now let's code this thing. Our goal is to have three bands of brightness across the screen: The top should be black, the middle dark, and the bottom bright. So conceptually, how are we going to do this? What needs to happen to change the brightness?


If you cannot answer that question then you need to go back and reread sections one and two.

Go on, I can wait.

















Okay, we're going to use HDMA to set $2100 to #$00 at scanline 0, #$07 at scanline 75, and #$0F at scanline 150 (It doesn't have to be at those exact scanline positions, but those roughly cut the screen into thirds). But before we can do that, we need to learn about HDMA tables.

Lesson 4: HDMA Tables



As I mentioned before, a(n) HDMA table is a table that contains the data for your HDMA effects. If you don't know what a table is, please go read an ASM tutorial, and how did you make it this far not knowing that? Anyway, a standard HDMA table looks like this:

Code
HDMATABLE: db $30,$00 db $01,$01 db $01,$02 db $01,$03 db $01,$04 db $00


Note that it doesn't have to be split up into two byte chunks, it's just like that to make it easier to read, as you'll see.

Now let's pick this apart. First off, we sort of read this backwards. In the first line, the the second byte says to write #$00 to the given register, then to wait for #$30 scanlines before moving on to the next line. So if we're using $2100 as our register, then this will set $2100 to #$00 on scanline #$00. Now for the next line. That one says that we will set the given register to #$01, then wait #$01 scanlines. In our example, this would set $2100 to #$01 on scanline #$30. By the scanline the given register will be set to #$02. It keeps going like that until it reads the "wait this many scanlines" byte as being #$00, at which point it stops until the next frame. It is very important you remember that #$00, otherwise you'll get all sorts of strange visual effects.

So, what brightness is the screen at scanline #$33? How about scanline #$40?

Answers: #$04 and #$04 respectively.

If you didn't get those right, you have some concept mixed up. Reread the previous section or ask for help.

Lesson 5: Putting It Together



Okay, we're just about ready for your first HDMA effect-thing. There's just one more quick thing. Recall I mentioned very briefly about HDMA channels? I'll go ahead and explain that now. You can "run" up to 8 HDMA effects at a time, numbered 0 - 7. Super Mario World uses most of these already for things like the keyhole effect and end goal iris out, and messing with the HDMA on those channels would be a not-very-good thing. So we are limited to only using channels 3, 4, and 5.

Alright, you know all the basics of HDMA! Let's code us some code! This code needs to go somewhere that will be run in a blank, and the only easy way to do that is to stick it in levelINITASM. So do that.

We need to set the appropriate HDMA registers. To make it easy, let's go in order.

Code
LDA #$00 STA $4330


You with me so far? We take #$00 and store it into $4330. Recall that $43x0 should (for now) always be set to #$00. Also recall that the x should be replaced with the current channel we're using. We're arbitrarily using channel three, so we write to $4330. If we used channel 4 we'd write to $4340. Get it?

Code
LDA #$00 STA $4331


Yeah, this is kind of a boring combination. We're also writing #$00 to $43x1, because $2100 is the brightness register. Yep.

Code
LDA.b #HDMATable STA $4332 LDA.b #HDMATable>>8 STA $4333 LDA.b #HDMATable>>16 STA $4334


Whoa, crazy! 6 opcodes at once! Alright, here's what we're doing. First, assume that HDMATable points to our HDMA Table. What this code does is set the registers to the address of the HDMA Table we're using. If you don't get exactly what this particular code does, that's fine; it's kind of weird anyway. I give you permission to copy-paste this and only this bit of code, but if you're brave, here's what's going on: we load the address of HDMATable as a byte-width value (hence the .b), which defaults to the low byte, and store it in $43x2. Then we load the address of HDMATable, get the high byte, and store it in $43x3. Finally, we get the bank byte of #HDMATable and store it in $43x4. If you understood that, good for you. Like I said, if you comprehend it well enough that you can just copy-paste it then that's fine too.

Code
LDA #$08 TSB $0D9F


This tells the Super Mario World engine that we're using HDMA channel 3 (0000 1000). If we were using channels 3 and 4, we'd LDA #$18 instead (0001 1000).

Code
RTS HDMATable: ; Build this yourself!! There will be a cheat sheet below, but if you ; don't know what goes here, then you're misunderstanding something!! ; Remember that we want to set the brightness to #$00 at the top, ; #$07 1/3 of the way down, and #$0F 2/3 of the way down the screen.


Note: The RTS, as you should know, is to prevent the HDMA Table from being read as code, which would be a bad thing.























Code
RTS HDMATable: db $4A,$00 db $4A,$07 db $4A,$FF db $00


Okay, so let's put the whole thing together! First try to build it, from scratch, on your own.


I'll wait. It's important that you try this yourself. Your result should look like this:




























Alright, did you get it? If not, figure out where you went wrong and try it again. If you really can't figure it out, there's a cheat sheet below, but really, try to get it on your own. You're not helping anyone by just copying and pasting the answer.














Code
LDA #$00 STA $4330 LDA #$00 STA $4331 LDA.b #HDMATable STA $4332 LDA.b #HDMATable>>8 STA $4333 LDA.b #HDMATable>>16 STA $4334 LDA #$08 TSB $0D9F RTS HDMATable: db $4A,$00 db $4A,$07 db $4A,$0F db $00


Now, obviously, this isn't much of a gradient (which I'm sure is what you're here for, isn't it). So, how would you go about making an actual gradient? Just make the intervals between each write smaller. Instead of waiting #$4A scanlines, only wait 4 or 5. For example:

Code
HDMATable: db $04,$00 db $04,$01 db $04,$02 db $04,$03 db $04,$04 db $04,$05 db $04,$06 db $04,$07 db $04,$08 db $04,$09 db $04,$0A db $04,$0B db $04,$0C db $04,$0D db $04,$0E db $04,$0F db $00


The result will look something like this:



One last thing before we move on: The "wait this many scanlines" byte cannot be #$80 or greater. ...well, it technically can, but that involves some more complicated concepts that won't be covered in this tutorial. For now, if you need to wait more than #$7F scanlines, just split the wait into 2 and set the same value twice (db $50,$07 : db $50,$07, for example).

Lesson 6: The Good Stuff



Okay, you've been waiting for this. Let's get to color gradients!

Note: I'm going to be going a bit quicker here, because by now I assume that you completely understand every single thing I've gone over. You know the deal by now, if you're fuzzy on something, don't move on, go back and review. Ask questions. Practice. Try making your own darkness gradients. Then come back here.

So, looking back at regs.txt (or my short list above) you can see that the register that controls the background color is $2132. Now, I assume you know some things about color. You should know that's every color has a red, green, and blue component to it, which combined can make (just about) every color. So, knowing that, why aren't there three registers for the background color? Because the SNES dev team decided to make things difficult, that's why. Here's how it works. When you write to that register, your write must be in the following format:

bgrccccc

If the "b" bit is set, then "ccccc" will affect the blue portion of the background for that write. If "g" is set, then "ccccc" affects the green portion. If "r" is set, then "ccccc" affects the red portion. So to make the background some gray color, you'd write #$90, then #$50, then #$30 to $2132 (examine their bits to see why). This means that if you want to get a color that uses red, green, and blue, then you're going to need to write to that address three times. This also means you will need three HDMA tables. So let's tackle this.

Code
LDA #$00 STA $4330 ; Set the transfer mode. Again, normally advanced stuff; don't worry about it right now. STA $4340 ; What you should worry about is the fact that we're setting the data for 3 channels here! STA $4350 ; Notice we set channel 3, 4, and 5 to the same value, which is usually what you want. LDA #$32 ; And again. We set channels 3, 4, and 5 to the BG Color register. STA $4331 STA $4341 STA $4351 ; Now here's where the channels differ. We need a separate table for each channel. ; One channel will handle the blue color, one the green, and one the red. LDA.b #BlueTable STA $4332 LDA.b #BlueTable>>8 STA $4333 LDA.b #BlueTable>>16 STA $4334 LDA.b #GreenTable STA $4342 LDA.b #GreenTable>>8 STA $4343 LDA.b #GreenTable>>16 STA $4344 LDA.b #RedTable STA $4352 LDA.b #RedTable>>8 STA $4353 LDA.b #RedTable>>16 STA $4354 LDA #$38 TSB $0D9F RTS ; Now for the tables. ...here we go. BlueTable: db $36,$83 db $06,$84 db $06,$85 db $06,$86 db $06,$87 db $06,$88 db $06,$89 db $06,$8A db $06,$8B db $06,$8C db $06,$8D db $06,$8E db $06,$8F db $06,$90 db $06,$91 db $06,$92 db $00 GreenTable: db $36,$46 db $06,$47 db $06,$48 db $06,$49 db $06,$4A db $06,$4B db $06,$4C db $06,$4D db $06,$4E db $06,$4F db $06,$50 db $06,$51 db $06,$52 db $06,$53 db $06,$54 db $06,$55 db $00 RedTable: db $30,$34 db $06,$35 db $06,$36 db $06,$37 db $06,$38 db $06,$39 db $06,$3A db $06,$3B db $06,$3C db $06,$3D db $06,$3E db $06,$3F db $00




Phew! Alright, notice a few things. First off, all the red values are between #$20 and #$40, all the green values are between #$40 and #$60, and all the blue values are between #$80 and #$A0. This is because any larger a change and they would end up switching colors. (#$3F + #$01 = #$40, which sets the green bit). Also notice that RedTable is shorter than GreenTable and BlueTable. This is perfectly fine. (Finally, notice that the resulting gradient is ugly, since I just threw random values in there, but at least it's nicer looking than that ugly default tanish color a lot of SMW levels have.)

Now, that's a lot of work, working out what value all the tables should have to get the nice colors you want. Mercifully, however Ersanio was kind enough to create a tool to do it for you, provided you have an image of the gradient you'd like. Get it here. Note, however, that you'll need to change two things, because this tool optimizes things in a way that beyond of the scope of this tutorial.

The tool outputs two tables, despite the fact that you normally need three. To accomidate for this (and supposing you're using channels 3 and 4), you will need to store #$02 to $4330 and #$00 to $4340, then have HDMA channel 3 point to the first table the tool outputs, and channel 4 point to the second table it outputs. Past that it is pretty much like any other gradient, though it leaves open one extra channel for you to do whatever with.

Now, go practice. Make your own gradients, be they of darkness or color. Practice some more. And even if you think you've gotten it perfectly and you're bored stupid with this nonsense go and practice it even more. Make sure you know what's going on. Experiment. Change values and try to guess what will happen. If you were wrong, figure out why. Go. It can only be beneficial to you.





Congratulations! You now know the basics of HDMA (That is, if you really get this stuff. If you don't, go back and reread it. Practice. Really, make your own problems and solve them. "How would I get this effect?" Go do it. Now.)! I now highly recommend you check out Kaijyuu's tutorial, which covers more advanced topics like putting HDMA tables in RAM to you can modify them on the fly, color math, and all sorts of other cool stuff.

If you have any comments or questions, feel free to ask them here. I'll answer them whenever possible. In particular, if I messed anything up, which, given the fact that I wrote this somewhat quickly, is very possible, please tell me and I'll go fix it.
Last edited on 2011-12-10 02:27:02 AM by Kipernal.
Oh wow. This explains a lot, and in a very nice manner.
Thanks a lot Kip ^-^

And now to move on to kaijyuus >:3
Wow, this is just awesome!. I could understand everything I couldn't before! Thanks for the tutorial :)
Excellent tutorial, Kipernal - it leaves no open questions whatsoever, and ensures people actually know what they're doing. I already knew most of what you went over here, and still it helped me deepen that knowledge greatly. Fantastic job.

I only wish there were more advanced HDMA tutorials like this (windowing in particular).
Last edited on 2011-11-12 07:26:11 AM by WhiteYoshiEgg.
This tutorial looks very interesting, and I want to try it, but in order to do this, do I need any previous knowledge about ASM coding? Thanks in advance
Originally posted by JTA777
This tutorial looks very interesting, and I want to try it, but in order to do this, do I need any previous knowledge about ASM coding? Thanks in advance


Originally posted by Kipernal
you MUST understand the following concepts in ASM:

-How to use it


That would be a yes. You need to be at least somewhat literate in ASM.
Originally posted by Kipernal
Originally posted by JTA777
This tutorial looks very interesting, and I want to try it, but in order to do this, do I need any previous knowledge about ASM coding? Thanks in advance


Originally posted by Kipernal
you MUST understand the following concepts in ASM:

-How to use it


That would be a yes. You need to be at least somewhat literate in ASM.



Darn... Looks like it'll be some time before I can learn this. Any really good tutorials you know of?? (I've checked out a few, but I just don't entirely get them).
Originally posted by JTA777
Darn... Looks like it'll be some time before I can learn this. Any really good tutorials you know of?? (I've checked out a few, but I just don't entirely get them).


Any of the ones in this subforum, really. They're pretty much all good.
I'm confused. You kinda contradict yourself here:

Originally posted by Kipernal

You see, most of these registers can only be written to during a blank.
...we can not get code to run during a blank



Also tell me if I'm getting the concept: (This was copied from you, but I'm trying to see if I understand it correctly).
Code
db $36,$83 db $06,$84 db $06,$85 db $06,$86 db $06,$87 db $06,$88 db $06,$89 db $06,$8A db $06,$8B db $06,$8C db $06,$8D db $06,$8E db $06,$8F db $06,$90 db $06,$91 db $06,$92 db $00


So everthing in the left column is telling the machine how long each line of color will be, and the right colomn is telling the machine what the color is? right?

And one last question, how do you insert this into your hack?
Last edited on 2011-11-30 07:46:19 PM by JTA777.
Originally posted by JTA777
I'm confused. You kinda contradict yourself here:

Originally posted by Kipernal

You see, most of these registers can only be written to during a blank.
...we can not get code to run during a blank


That's what HDMA is for. Because you can't run code during a blank, HDMA will set the registers for you during the blanks that you specify.


Originally posted by JTA777
Also tell me if I'm getting the concept: (This was copied from you, but I'm trying to see if I understand it correctly).
Code
db $36,$83 db $06,$84 db $06,$85 db $06,$86 db $06,$87 db $06,$88 db $06,$89 db $06,$8A db $06,$8B db $06,$8C db $06,$8D db $06,$8E db $06,$8F db $06,$90 db $06,$91 db $06,$92 db $00


So everthing in the left column is telling the machine how long each line of color will be, and the right colomn is telling the machine what the color is? right?


Mostly; it's not how long each line of color is, it's how tall.

Originally posted by JTA777
And one last question, how do you insert this into your hack?


Put the code in the init portion of levelASM.
Originally posted by Kipernal
...blah blah
Code
LDA.b #RedTable STA $4352 LDA.b #RedTable>>8 STA $4353 LDA.b #RedTable>>16 STA $4354 LDA #$38 TSB $0D9F RTL

...blah blah ...


The RTL here is wrong (I hope it was just a typo =P)


EDIT: Uh, also, this is a really useful tutorial!
Last edited on 2011-12-05 04:08:34 PM by Lui37.
Originally posted by Lui37
The RTL here is wrong (I hope it was just a typo =P)


I meant to reply to this and fix the issue five days ago, but apparently it slipped my mind. The error was because I was using LevelASMTool, which requires RTL instead, and I forgot to change back that one RTL, apparently. I'll go and (actually) fix it now.

Thank you for telling me, no thanks to me for forgetting. (derp)
Last edited on 2011-12-10 02:27:23 AM by Kipernal.
Thanks a LOT! It really helped me!

At least for brightness HDMA ):
Whenever I make a gradient code my ROM crashes, even with yours. I can't see why this happens. I'm putting the code in levelINITcode.asm.

cmd.exe shows this:
error: levelinitcode.asm: line XX: string [BlueTable] already defined [BlueTable:]
error: levelinitcode.asm: line XX: string [GreenTable] already defined [GreenTable:]
error: levelinitcode.asm: line XX: string [RedTable] already defined [RedTable:]
Last edited on 2011-12-10 10:46:39 AM by MaxodeX.
Looks like your table has the same name as another. Try changing your table names.
Originally posted by wiiqwertyuiop
Looks like your table has the same name as another. Try changing your table names.

Huh? My code is the only code running in the entire INIT. Here's the code:
Code
LDA #$00 STA $4330 STA $4340 STA $4350 LDA #$32 STA $4331 STA $4341 STA $4351 LDA.b #Blue STA $4332 LDA.b #Blue>>8 STA $4333 LDA.b #Blue>>16 STA $4334 LDA.b #Green STA $4342 LDA.b #Green>>8 STA $4343 LDA.b #Green>>16 STA $4344 LDA.b #Red STA $4352 LDA.b #Red>>8 STA $4353 LDA.b #Red>>16 STA $4354 LDA #$38 TSB $0D9F RTS Blue: db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $0A,$9F db $00 Green: db $0A,$51 db $0A,$52 db $0A,$53 db $0A,$54 db $0A,$55 db $0A,$56 db $0A,$57 db $0A,$58 db $0A,$59 db $0A,$5A db $0A,$5B db $0A,$5C db $0A,$5D db $00 Red: db $0A,$21 db $0A,$22 db $0A,$23 db $0A,$24 db $0A,$25 db $0A,$26 db $0A,$27 db $0A,$28 db $0A,$29 db $0A,$2A db $0A,$2B db $0A,$2C db $0A,$2D db $00

Not sure if it works because I cannot test it. But yeah, this is it.
Originally posted by Maxodex
Originally posted by wiiqwertyuiop
Looks like your table has the same name as another. Try changing your table names.

Huh? My code is the only code running in the entire INIT. Here's the


How about MAIN? Does any table in there have the same name as the ones in INIT?
Wow, I forgot to remove it from levelcode.asm. Thanks a lot Wiiq! Also thanks to Kipernal for this amazing tutorial. You guys are livesavers!
Last edited on 2011-12-10 12:06:35 PM by MaxodeX.
Pages: « 1 »
Forum Index - SMW Hacking - General SMW Hacking Help - Tutorials - Kipernal's Guide for Beginners to HDMA

The purpose of this site is not to distribute copyrighted material, but to honor one of our favourite games.

Copyright © 2005 - 2013 - SMW Central
Legal Information - Link To Us


Total queries: 27

Menu