View Full Version : [Tutorial] Yet another ASM-Tutorial

October 2nd, 2010, 11:40 AM
This is a tutorial by knizz and FullMetal about ASM for the Gameboy Advanced. All of this is based on our own experience and the incredibly useful GBATEK (http://nocash.emubase.de/gbatek.htm) which is a detailed reference of the GBA. It doesn't explain how to use its knowledge though. That's what I want to do better. You should at least know how to calculate in hex and understand bit-wise-and and bit-shifting before reading this. Basically the GBA consists of two main components: The memory and the processor.

The memory has many slots numbered in 8-digit long hexadecimal numbers and can store bytes which are numbers between 0x00 and 0xFF. To store higher numbers two bytes are used together in reverse order. 0x1234 (2 bytes) would be stored in the memory as 0x34 and 0x12. The same applies to 4-Byte numbers. A position in memory can also be called address, offset or pointer. (The last two terms mean actually something else but they are used anyway) 2-Byte numbers can only start at even addresses (hex ends with 0, 2, 4, 6, 8, A, C or E) and 4-byte numbers only at every fourth address (hex ends with 0, 4, 8 or C). Not all adresses are connected to a memory-block. For example: All addresses starting with 04 (like 04000000 or 040B7A34) are connected to the graphics-chip. Other addresses contain the current state of the buttons, etc. A complete map can be found in the GBATEK.

The Processor (or CPU) can't do anything but reading from memory, calculating and writing back to the memory. Even the instructions (also called code or program) for the processor come from the memory. The art of programming is to write human thoughts as series of read and write instructions. The more programming-experience you have the easier it will be for you to understand them.

Something very confusing is the use of the word ASM (short form of Assembly). The real meaning is the text representation of the instructions. But is also used to name what should be called machine code (which is stored as numbers). Programs can convert the machine-representation of the instructions into the text/asm-representation. This process is called disassembling. Warning: These programs can't tell the difference between data (images, music) and code. If you try to disassemble data the you won't get error messages. Just nonsense instructions.

The processor in the GBA was designed by ARM. It has two operation modes. One uses 4-Byte instructions and is called ARM too. The other mode uses 2-Byte instructions and is called THUMB. Games use THUMB for nearly everything. Only sometimes it's necessary to use ARM.

The GBA-CPU has 16 Registers: R0, R1, ... R11, R12, SP, LR and PC. These are very fast 4-Byte memories. The last three have special meanings:

SP contains the address of the Stack (explained later)
LR contains the return-address (explained later)
PC contains the address of the instruction to be executed.

In THUMB-Mode you only have limited access to the second half of the registers (R8 upwards.)

Setting PC to an address is called jumping, branching or goto-instruction. In THUMB-Mode the branching-instruction "b" is the only one that can depend on a condition. The other instructions can be made conditional by skipping over them with a conditional "b". Here are a two examples how branches are used:

Code to find the image of a pokemon (if-else-construction)
0000: compare pokemon_numer to 201
0002: branch to 0020 if not equal

0004: ... find the picture for unown ...
001E: branch to 0050

0020: ... find the picture for a normal pokemon ...
003E: branch to 0050

0050: end

Code for a game-main-loop (loop-construction)
0000: ... handle keypresses ...
0100: ... calculate damages etc. ...
0200: ... draw the scene ...
0300: ... provide a few milliseconds of music ...
0400: ... wait for the next frame ...
0410: compare quit to "yes"
0412: branch to 0000 if not equal
0414: ... game over ...

When a task is very repetitive a programmer makes a function. This function can be started (or called) from everywhere in the program. When the function finishes the execution resumes at the point the function was called. And it works like this:

The calling code saves its PC to LR.
It jumps to the start of the function
The processor continues executing at PC and eventually reaches the end of the function
The last instruction says: Jump to LR (This instruction is also called return)
The calling code resumes

Complex games can have over 5000 functions. Here is an example:

Function for finding a pokemon image by number (which is saved in R1)
0200: ... code for battle ...
0280: copy the id of the pokemon to draw into R1
0282: call 0800 to get the image of the pokemon (this sets LR to 0284 and PC to 0800)
0284: call 1400 to draw it on the screen (this sets LR to 0286 and PC to 1400)
02FE: ... end of battle-code ...


0400: ... code for evolution ...
0450: copy the id of the pokemon to draw into R1
0452: call 0800 to get the image of the pokemon (this sets LR to 0454 and PC to 0800)
0454: call 1400 to draw it on the screen (this sets LR to 0456 and PC to 1400)
04FE: ... end of evolution-code ...


0800: compare R1 to 201
0802: bne 0820

0804: ... find the picture for unown and save its offset to R2 ...
081E: b 0850

0820: ... find the picture for a normal pokemon and save its offset to R2 ...
083E: b 0850

0850: b LR


1400: ... draw the image specified by R2 on the screen ...
14FE: b LR

Functions in Functions
The approach above is very useful but it has two big problems. First it doesn't support functions in functions. A second call would overwrite the LR from the first call and create an endless loop at the second return. And secondly the called function could overwrite the registers the calling code is using. The solution to both problems is the stack which is a memory that can be accessed by pushing (putting numbers at the too the stack) and popping (taking numbers from the stack). Every function that starts sub-functions begins with "push LR". Whatever happens to LR now (like sub-calls) the backup on the stack is unaffected. When the function finishes it uses "pop R0" to restore the value from LR to R0 and jumps back into the calling code using "goto R0". Btw. The instruction for calling is called "bl".
0200: ... code for battle ...
0280: copy the id of the pokemon to draw into R1
0282: bl 0800 (this sets LR to 0284 and PC to 0800)
0284: bl 1400 (this sets LR to 0286 and PC to 1400)
02FE: ... end of battle-code ...


0400: ... code for evolution ...
0450: copy the id of the pokemon to draw into R1
0452: bl 0800 (this sets LR to 0454 and PC to 0800)
0454: bl 1400 (this sets LR to 0456 and PC to 1400)
04FE: ... end of evolution-code ...


0800: push R1, R3, R4, R5 and LR ; Every register used in a function is pushed before
0800: cmp R1, 201
0802: bne 0820

0804: ... find the picture for unown and save its offset to R2 ...
0806: bl 1900 ; Calls a sub-function to determine the letter of the unown
; Even though "bl" overwrites LR a working copy lies on the stack
081E: bne 0850

0820: ... find the picture for a normal pokemon and save its offset to R2 ...
083E: b 0850

0850: pop R1, R3, R4, R5 ; Restores the registers in case the function changed them.
; It doesn't restore R2 because this is a way to pass a value to the calling function
; The calling function is aware of that.
0852: pop R0 ; Restores LR
0854: b R0


1400: ... draw the image specified by R2 on the screen ... ; this function doesn't have to push LR because it doesn't call sub-functions
14FE: b LR

Common Instructions (=Opcodes)
"mov a, b" copies the value of the register b to the register a

"ldr a, b" copies the value of the offset b to the register a
"ldrw a, b" like ldr loads 2 bytes instead of 4
"ldrb a, b" like ldr loads 1 bytes instead of 4

"str a, b" copies the value of he register a to the offset b
"strw a, b" like str loads 2 bytes instead of 4
"strb a, b" like str loads 1 bytes instead of 4

Sometimes the ldr and str opcodes have a third argument which is added to the first.

"lsl a, b, c" shifts the value of register b c bits to the left and stores it in register a
"lsr a, b, c" like lsl but shifts to the right
A combination of lsl and lsr is often used to cut off higher bits:
lsl R0, R0, #0x18
lsr R0, R0, #0x18
"cmp a, b" compares the numbers of the register a and the register or number b
"b a" jumps to address a
"bx a" jumps to address in register a and switches to ARM-mode depending on the LSB. 1=THUMB 0=ARM.
"bl a" calls a. Saves the address of the next instruction to LR.
"beq" "bne" like b but only jumps when the last comparison result is "EQual" or "Not Equal". Read the GBATEK for more condition codes.

A real life example
As you know you can't move the cursor of the town map (firered) out of a certain area. The goal of this hack is to increase this size. What you need is VBA and VBA-SDL-H. The first thing you have to do is to find where the position is saved in memory. Then you have to find and understand the code that accesses it. And the last thing is to change the code to allow a bigger range.

Finding the cursor-position via cheat-finder
Open VBAs cheat finder and look for all numbers that are not zero. Then move the cursor. Search for all numbers that changed since the last search. Then let the game run for a few seconds without moving the cursor. Search for all numbers that haven't changed since the last search. Repeat this until you can narrow down the possible positions to 5 or 10. (The VBA cheat finder does this automatically. Every search operates on the result of the last search. That means if you exclude one result from your search results it won't show up again even if you set the correct conditions. To reset the cheat-finder press "Start".)
Unfortunately this method doesn't work for the cursor.

Finding the cursor-position via writing breakpoint
There is a technology called breakpoints. They stop the programm when it either reads, writes or executes a certain address in memory. You can use a breakpoint that triggers when the position of the cursor is written to the video-ram. As written in the GBATEK there are two types of graphics: Tiles and Objects. The cursor is obviously an object because it can move in pixel-steps instead of tile-steps. If you open the VRAM-viewer of VBA you can see that it's the first object in memory. And the attributes of the first object are saved at 07000000. Okay. Now start VBA-SDL-H. This version of VBA doesn't have a graphical interface. To open the ROM you have to drag it onto the exe-file. Play the game until you get the map. Press F11. This pauses the game and start the debugger in the console-window. To get a list of possible commands type "?" and press enter. At this point the most useful command is "save 1" which saves the current game. The next command you need is "bpw 07000000 6" which stands for "breakpoint on write from 07000000 to 07000006". WARNING: The first number is written in hex. The second in decimal. The command "c" for continue resumes the game. However it stops immediately because of the breakpoint. Now you are at the position where the cursor position is written to VRAM. You should see something like:

Breakpoint (on write) address 07000000 old:503f0040 new:503f0040
Breakpoint (on write) address 07000004 old:01005130 new:01005130

R00=03003128 R04=00000000 R08=00000000 R12=00000010
R01=07000000 R05=030030f0 R09=00000000 R13=03007e0c
R02=04000100 R06=030030e4 R10=00000000 R14=08007341
R03=03003fb0 R07=030030f0 R11=00000000 R15=081e3b68
CPSR=0000003f (......T Mode: 1f)

081e3b64 df0b swi $0b
> 081e3b66 4770 bx lr
081e3b68 df06 swi $06

The first part shows which breakpoint stopped the game and why. Then next part shows the registers. The last part shows the previous, current and next instruction. Because writing-breakpoint only trigger *after* the writing instruction is showed as previous instruction. The next instruction is irrelevant because the execution never reaches this point. "bx lr" indicates the end of a function. To get a better overview you can type "dt 081e3b50". This disassembles the next 20 instructions after the specified address. I used an address that is slightly lower than our current point of execution to see what happened before. But there's only a "bx lr" (end of function) right above 081e3b64. Conclusion: We are in a function which consists of two instructions: "swi $0b" and "bx lr". SWI is the BIOS-instruction. Here is the explanation from GBATEK:

SWI 0Bh (GBA/NDS7/NDS9) - CpuSet
Memory copy/fill in units of 4 bytes or 2 bytes. Memcopy is implemented as repeated LDMIA/STMIA [Rb]!,r3 or LDRH/STRH r3,[r0,r5] instructions. Memfill as single LDMIA or LDRH followed by repeated STMIA [Rb]!,r3 or STRH r3,[r0,r5].
The length must be a multiple of 4 bytes (32bit mode) or 2 bytes (16bit mode). The (half)wordcount in r2 must be length/4 (32bit mode) or length/2 (16bit mode), ie. length in word/halfword units rather than byte units.
r0 Source address (must be aligned by 4 for 32bit, by 2 for 16bit)
r1 Destination address (must be aligned by 4 for 32bit, by 2 for 16bit)
r2 Length/Mode
Bit 0-20 Wordcount (for 32bit), or Halfwordcount (for 16bit)
Bit 24 Fixed Source Address (0=Copy, 1=Fill by {HALF}WORD[r0])
Bit 26 Datasize (0=16bit, 1=32bit)

So "swi $0b" copies words and half-words from the address in R00 to the address in R01. And now guess whats in R01. It's 07000000. That means that you are on the right track. Now it's interesting which function called the one we're inside at the moment. Use "n" for "next". Now you see:

081e3b66 4770 bx lr
> 08007340 bc01 pop {r0}
08007342 4700 bx r0

The instruction calling the memory-copying-function is right before 08007340. To see it you can use "dt" again. ("dt 08007320" to be specific). Here is the result. I recommend reading it the order of the number next to the comments.

08007320 b500 push {lr} // 9. indicates the beginning of a function (but not always)//
08007322 4a08 ldr r2, [$08007344] (=$030030f0)
08007324 4908 ldr r1, [$08007348] (=$00000439) // and this//
08007326 1850 add r0, r2, r1 // and this//
08007328 7801 ldrb r1, [r0, #0x0] // and this//
0800732a 2001 mov r0, #0x1 // and this//
0800732c 4008 and r0, r1 // and this//
0800732e 2800 cmp r0, #0x0 // 8. you don't need to worry about the condition for the conditional jump which doesn't happen in our case so ignore this//
08007330 d106 bne $08007340 // 7. this instruction would skip the rest. the fact that the breakpoint triggered shows that it wasn't skipped.//
08007332 1c10 add r0, r2, #0x0 // 5. Write R02 to R00. The value of R02 comes from 08007322. (a few lines above)//
08007334 3038 add r0, #0x38 // 6. 0x38 is added to R00 making it 03003128//
08007336 21e0 mov r1, #0xe0 // 4. This is a trick to save memory. Instead of using the whole number 07000000 which would use up 50% more memory ...//
08007338 04c9 lsl r1, r1, #0x13 // 5. ... the code assigns 0xe0 to R01 and then bitshifts it to get 07000000 as result.//
0800733a 4a04 ldr r2, [$0800734c] (=$04000100) // 3. This is where the content of R02 comes from. It's a fixed number.//
0800733c f1dc bl $081e3b64 // 2. This called the memory-copying-function which triggered your breakpoint//
08007340 bc01 pop {r0} // 1. YOU ARE HERE !!!!!//
08007342 4700 bx r0

It seems like the cursor data comes from 03003128 AND this address doesn't change because it's the sum of two fixed numbers: 030030f0 and 0x38. Let's verfiy this in the normal VBAs memory viewer. Don't forget to tick "Automatic Update" in the memory-viewer. The numbers change only when you move the cursor. BIG SUCCESS!

Finding the limiting code
For this next problem there are again two ways to approach it. You can either use another breakpoint on 03003128 or use IDA Pro. With IDA its very comfortable to analyze ASM-Code but because you need the full-version to use it for Gameboy Advanced I will show you how it works with breakpoints. First delete your old breakpoint with "bpwc". Then make the new one with "bpw 03003128 1". Use "c" and look at the next breakpoint-stop:

Breakpoint (on write) address 03003128 old:403c0074 new:403c0074
R00=403c0074 R04=0202063c R08=00000000 R12=00000040
R01=00000804 R05=03003529 R09=00000000 R13=03007df0
R02=03003128 R06=030030e4 R10=00000000 R14=08006f35
R03=03007df8 R07=030030f0 R11=00000000 R15=08008aa2
CPSR=0000003f (......T Mode: 1f)
08008a9e 6010 str r0, [r2, #0x0]
> 08008aa0 6051 str r1, [r2, #0x4]
08008aa2 7818 ldrb r0, [r3, #0x0]

Again also use "dt". Just a few instructions above you can find:

08008a9a 6820 ldr r0, [r4, #0x0] // loads r0//
08008a9c 6861 ldr r1, [r4, #0x4] // loads r1//
08008a9e 6010 str r0, [r2, #0x0] // saves r0, this triggered the breakpoint//
08008aa0 6051 str r1, [r2, #0x4] // saves r1, YOU ARE HERE

This means that you're still not at the source of the cursor position. This code just copies it from 0202063c. (found in R04). Use the same method again. Delete all breakpoints. Create a new one. Continue.

Breakpoint (on write) address 0202063c old:74 new:74
R00=00000174 R04=00000000 R08=00000000 R12=02020bcb
R01=0000007c R05=000001ff R09=00000000 R13=03007df8
R02=0000403c R06=fffffe00 R10=00000000 R14=08006baf
R03=0202063c R07=0202063c R11=00000000 R15=08006ca8
CPSR=0000003f (......T Mode: 1f)
08006ca4 7018 strb r0, [r3, #0x0]
> 08006ca6 1c60 add r0, r4, #0x1
08006ca8 0600 lsl r0, r0, #0x18

This time I'll skip the explanation. This function adds together the values of 0202063c+0x22(halfword), 0202063c+026(halfword) and 0202063c+0x29(byte). The second and third value are only offsets. We're still not at the source. Look for a code that writes to 0202063c+0x22 (=0202065e).

Breakpoint (on write) address 0202065e old:007c new:007c
R00=0000007c R04=0202063c R08=00000000 R12=00000040
R01=0202063c R05=0202067a R09=00000000 R13=03007e00
R02=0200811c R06=00000000 R10=00000000 R14=08006b83
R03=00000002 R07=00000001 R11=00000000 R15=080c3006
CPSR=0000003f (......T Mode: 1f)
080c3002 8448 strh r0, [r1, #0x22]
> 080c3004 bc01 pop {r0}
080c3006 4700 bx r0

This function is the first one that doesn't read from a fixed position. Instead the position is given by the value at 020399E4 plus 2. However the value 0200811c doesn't seem to change (via memory-viewer). So breakpoints will still work.

Breakpoint (on write) address 0200811e old:000b new:000a
R00=0000000a R04=020399e4 R08=00000000 R12=00000040
R01=0200811c R05=0000000a R09=00000000 R13=03007dec
R02=0000000a R06=030030e4 R10=00000000 R14=080c340d
R03=00000008 R07=030030f0 R11=00000000 R15=080c339c
CPSR=2000003f (..C...T Mode: 1f)
080c3398 8048 strh r0, [r1, #0x2]
> 080c339a f7fd bl $080c0e20

If you disassemble hundert instructions before this position you will find four similar blocks. Two of them have a ADD 1 instructions. The other two have SUB 1 instructions. There is one for each direction. They move the cursor. But they don't have border-checks. They just move the cursor into the direction specified in 0200811c+0x8 and 0200811c+0xa.

Breakpoint (on write) address 02008124 old:0000 new:0000
R00=080c31c1 R04=0200811c R08=00000000 R12=00000040
R01=080c0514 R05=00000000 R09=00000000 R13=03007de8
R02=00000000 R06=030030e4 R10=00000000 R14=080c340d
R03=020399e4 R07=030030f0 R11=00000000 R15=080c31cc
CPSR=4000003f (.Z....T Mode: 1f)
080c31c8 8125 strh r5, [r4, #0x8]
> 080c31ca 8165 strh r5, [r4, #0xa]
080c31cc 4a2b ldr r2, [$080c327c] (=$030030f0)

This function just sets the speed to zero :( Prevent the breakpoint from stopping here with "db 080c31c8" or "db 080c31ca". Idk.

Breakpoint (on write) address 02008124 old:0000 new:fffe
R00=0000fffe R04=0200811c R08=00000000 R12=00000040
R01=0200811c R05=00000000 R09=00000000 R13=03007de8
R02=030030f0 R06=020399e4 R10=00000000 R14=080c340d
R03=00000000 R07=030030f0 R11=00000000 R15=080c3236
CPSR=2000003f (..C...T Mode: 1f)
080c3232 8108 strh r0, [r1, #0x8]
> 080c3234 2501 mov r5, #0x1
080c3236 8dd3 ldrh r3, [r2, #0x2e]

Here is the code that controls the range of the cursor. These are the relevant lines:
080c31de: cmp r0, #0x00
080c31f8: cmp r0, #0x0d
080c3212: cmp r0, #0x14
080c322c: cmp r0, #0x00

The machine representation of the "cmp r0, #??"-instruction is [number][0x28]. So "cmp r0, #0x14" is 0x14 0x28 in memory. Changing the range of the cursor is now very easy. Just go to the four offsets with the comparisons change the numbers to your new limits and save it. You can use the memory viewer of VBA as hexeditor.

Just because the cursor can move freely it doesn't mean that the map works. You also need to change:
ROM:080C41B2 MOV R2, #0x16
ROM:080C41B2 MOV R2, #<insert new width + 1 here>
Then, repoint the respective data, and enlarge according to your new width.

ROM:080C4194 map0_base ; DATA XREF: get_worldmap_value:load_map_0_offsetr
ROM:080C4194 DCD 0x83F2490 ; you need to change this pointer
ROM:080C419C map1_base ; DATA XREF: get_worldmap_value:load_map_1_offsetr
ROM:080C419C DCD 0x83F2724 ; you need to change this pointer
ROM:080C41A4 map2_base ; DATA XREF: get_worldmap_value:load_map_2_offsetr
ROM:080C41A4 DCD 0x83F29B8
ROM:080C41A8 ; ---------------------------------------------------------------------------
ROM:080C41A8 load_map_3_offset ; CODE XREF: get_worldmap_value+28j
ROM:080C41A8 LDR R3, =0x83F2C4C ; load base for map #3
; --------------------------------------you need to change this pointer

That's it. We hope you enjoyed this tutorial.

knizz & FullMetal

PS: Probably huge parts of this tutorial are incomprehensible. Correction-suggestions are very welcome.

Shiny Quagsire
October 4th, 2010, 6:16 PM
Wow! I'm surprised nobody has replied! (Except him ^^) This is a great tutorial on hacking routines. It shows examples of how to set breakpoints, and how to hack it ;)

Although, I need to ask, does this expand the tilemap at all, or just the border?

October 4th, 2010, 9:53 PM
The tilemap for the graphics isn't considered here. The "tilemap" for interaction is mentioned in the last two boxes. You have to repoint and resize it yourself.

Full Metal
October 15th, 2010, 10:11 PM
Okayz...there's 3 parts to the worldmap:
1) Tileset
2) Tilemap
3) Map data
You have to manually expand the map data.
BTW KNIZZ, I WILL SOON GO TO THE....LEFT side of the world map :) because, our poorly written tut. doesn't cover that afaik...

hot darn
this is my yarn
keepin me partyin
till 8 oclock

lol random quote is random.

October 16th, 2010, 4:44 AM
Hi, im sortta new here so could i ask, like how do i "create" an entrance for a house. This is the situation: I enter a house in FR hacked rom and cant get out for some reason. The door graphic is there but i cant get out. plus i accidentally saved inside. Is there a way to "create" the exit?

Full Metal
October 24th, 2010, 3:17 PM
oh lord....look up an advance map tutorial...that's all I'll say.
ANYWAYS, what I really came here to post...
before we forget again lol.

November 26th, 2010, 6:20 PM
since I've never learned anything about ASM so far but still understand surprisingly great parts of what you're doin', I'll say nice tutorial xD
I don't understand everything and most of the steps not in detail, but I'm sure that's just because I don't know anything yet...hope that will change, though :)
*THUMBs up* xD

November 30th, 2010, 6:03 PM
Knizz, shiny quagsire, and full metal:

You guys are all great at writing half-tutorials. haha.

Knizz and full metal:
You explain everything in great detail and helps for understanding it, but lacks practical application, so it's difficult to stick everything in your mind when you have no use for it. You teach them what they are saying, but you throw it all at once. It's like trying to teach someone an entire language all at once, and then ask them to recite all the words back.

shiny quagsire:
You definitely help in practical application, but you lack the means of explanation, so it's harder to understand what you are teaching. You are good at getting someone to speak a language, and do it correctly, but they do not know what they are saying.

Now you three need to come together, say hi, spawn, and then let your spawn write a tutorial. :P Thanks for writing this, though. I am very glad you all have taken the time to try to teach the community advanced programming/hacking.

December 1st, 2010, 9:11 AM
hey... this tutorial is awesome..... i haven't read everything... but i will..... but i just wanna say... thanks....... you're helping loads of people......

December 18th, 2010, 10:41 AM
ROM:080C41B2 MOV R2, #<insert new width + 1 here>

Okay, I followed you up to this point. I changed the width, but can you explain more on re-pointing data relative to the new width?

December 18th, 2010, 3:31 PM
... but lacks practical application
What?! Isn't the whole second half of it practical application?!

can you explain more on re-pointing data relative to the new width?

Imagine a 3x3-map:

The data pointed to is ABCDEFGHI. On the map it looks like:

When you change the width from 3 to 4 it looks like:

Now you repoint the data to a place where there is place for 12 entries instead of 9. Write ABCxDEFyGHIz there.

December 18th, 2010, 3:58 PM
Great tut! It was very clear, and helped me alot.

December 30th, 2010, 11:36 AM
Hi knizz.
Can I translate this tutorial to Italian?
The only ASM tutorials in my language are from HackMew, so this will be very useful :)

December 30th, 2010, 12:42 PM
Hi knizz.
Can I translate this tutorial to Italian?
The only ASM tutorials in my language are from HackMew, so this will be very useful :)

Sure. I don't care at all.