Advertiser Content

Tutorial Mugshots via ASM

Started by Kyoko1 February 7th, 2014 3:09 PM
  • 30 replies



Seen February 26th, 2014
Posted February 26th, 2014
63 posts
6.1 Years

Mugshots via ASM

This time I would like to present you an improved version of my old tutorial..
Now the ASM reads from a table, which contains image pointer, palette pointer and pal-#.
I will explain you all the variables you must use and the table later.

We need:

thumb compiler

You also need inserted 64x64 sized mugshots and palettes for them.
If you don't know how to make this, visit my old tutorial here.
Its explained step-by-step there.

Building up the table

Open up your preferred hex-editor and load your ROM in it.
Now go to a location with much free space. I would recommend you
to keep space for lets say 0x180 bytes, which allows 32 mugshot-entries.

The table must be built up like this:
[image-pointer][palette-pointer][pal#][00 00 00]
First you need to reverse your image-offset and write it there, do the same
with the palette offset. But what is pal#? Well, we have access to 15 OAM palettes.
You can decide, which of these OAM palettes you want to use for this mugshot.
(Don't write a higher value than 0xF for this, or it crashes! [no more than 15 pals])

And if you don't know how to reverse offsets:

Let's say I got an image at 0xABCDEF and a palette at 0x123456
I split the offsets up into 3 parts: [AB] [CD] [EF] // [12] [34] [56]
Then I change the first and last block: [EF] [CD] [AB] // [56] [34] [12]
At last we add 08 behind it: EF CD AB 08 // 56 34 12 08

For example, my table could look like this:
Now repeat that for as much mugshots as you want.
Remember: The first entry of the table is INDEX 0x0.
The 2nd entry is INDEX 0x1 and so on.

Currently its only possible to display max. 2 images at the same time.
I failed at making the OAM-data 100 % dynamically in the RAM.
I will for sure fix this at the next version, as I nearly finished it.

Editing the ASM code

This time it gets easy:
.equ TABLE, 0x08(TABLE)
Replace (TABLE) with your table-offset in the ROM.

And the last thing you must do is changing all [OFFSET_OF_THIS_CODE]
to the offset you are going to insert this ASM code.
If you want it to insert it to
0x800000 for example, you
replace all [OFFSET_OF_THIS_CODE] with800000.

At the next version you don't need to do this..
For now you must

If you have done that, download the if you haven't done so before.
Extract it for example on your desktop.
Now put in the Loading.asm and Removing.asm into this folder.

Drag and Drop the Loading.asm to thumb.bat and the Removing.asm too.
You should get the files "Loading.bin" and "Removing.bin".

Open these 2 files and your ROM in your preferred hex-editor.
Firstly, mark all bytes in the Loading.bin. Copy them by pressing CTRL+C and
swap to the tab where your ROM is.
Go to the offset, which you inserted at "
[OFFSET_OF_THIS_CODE]" in the code.
Mark 0x11C bytes and press CTRL+V to replace our codes with the FF's.

Now swap over to the Removing.bin. Again, mark all bytes of the Removing.bin.
After that mark 0x40 bytes in your ROM file (right after the Loading.bin was) and
replace our Removing.bin with the FF's.

Note down the offsets where you inserted the 2 codes in the ROM and add +1 to them.
(F.E: 0x800000 gets to 0x800001; 0x83210C gets to 0x83210D)

Open AdvanceMap and XSE.
Write a script in XSE, which contains:

#dynamic 0x750000
#org @testscript
setvar 0x4500 0x0
setvar 0x4501 0x0
setvar 0x4502 0x0
callasm 0x(offset_of_your_loading.bin) +1 
msgbox @text 0x6
callasm 0x(offset_of_your_removing.bin)

#org @text
For explanation:

@/* VAR 0x4500 = SPRITE INDEX IN TABLE     */@
@/* VAR 0x4501 = LEFT OR RIGHT SIDE?        */@
@/* VAR 0x4502 = SPRITE SLOT IN SCRIPT        */@
At 0x4500, you choose your sprite which you want to load.
If you set this variable to 0x0, the first table-entry will be loaded.
If you set it to 0x1, the second will be loaded and so on.

At 0x4501 you can decide whether the mugshot should be on the
left or right side of the textbox: left = 0x0; right = 0x1

At 0x4502 you MUST write the sprite slot in the script.
If you are loading 1 mugshot in the script, you must set this var to 0x0
If you are loading another mugshot in the same script, you must set to 0x1!

Example of loading 2 sprites (like they are speaking with each other:

#dynamic 0x750000
#org @testscript
setvar 0x4500 0x0                              'first sprite
setvar 0x4501 0x0                              'left
setvar 0x4502 0x0                              'this sprite is the 1st one
callasm 0x(offset_of_your_loading.bin) +1
setvar 0x4500 0x1                              'second sprite
setvar 0x4501 0x1                              'right
setvar 0x4502 0x1                              'this sprite is the 2nd one
callasm 0x(offset_of_your_loading.bin) +1
msgbox @text 0x6
callasm  0x(offset_of_your_removing.bin) +1

#org @text
Let's check out the result:

Ofc the mugshots don't fit but I can't sprite, so..

Ending words

Thanks again for reading this tutorial and good luck on your romhack with it!
If you got any problem, feel free to ask in this thread. DON'T send me PMs!

I guess one or another person will have a question, because I didn't have any pictures
while explaining this times (too lazy )
Will check this thread out daily, so don't hesitate to ask here!

Give credits if you use this hack to:
-knizz (for research on OAM)

Original Tutorial:


Mugshots via ASM

Many of you probably used it in own hacks or at least you saw hacks with it..
Mugshots, which appeared at the top of textboxes. They look pretty cool, but
the most of them have major issues: A box, surrounding the image, and the
image itself is replaced with a Pokémon slot! To help many people and hacks, I
decided to make this tutorial. With a bit brain you soon have your own mugshot!

What do we need?

-64x64 sized image
-palette of the image
-Advance Palette Editor
-UnLZ gba
-thumb compiler- Download and extract to desktop
-Mugshot-showing routine - save to thumb folder
-Mugshot-hiding routine - save to thumb folder
(we dont need to edit the hiding routine though)

(The link-color looks crap with the newest style on PC (Y-Axis) :()

Inserting the image and the palette

I tried to provide as much images as possible to guarantee you a bugfree hack.
What you need to do now is to open the UnLZ Gba and your ROM in it.


Click on "Import" and choose your 64x64 indexed image. (Use ~Andrea's tool for indexing)
Now make a click on "Write to ROM".
You should see a pop-up with several checkboxes. Choose only the one in the picture:


Use FreeSpaceFinder to get an offset for the "Image Offset" in the pop-up.
(You shouldn't need more than 500 bytes though)
In my case, 0xB50000 is perfectly free ;)

Click ok, write down your Image Offset and exit the UnLZ Gba.


Now we're gonna insert the palette of our Mugshot. But first, open Irfanview and your image.


Now go to "Image -> Increase Color Depth", choose 256 colors and click ok.


After you've done that, go to "Image -> Palette -> Export Palette" and save it on the desktop.
Then just exit Irfanview and lets head over to the next step...
(Btw, APE gives an error when loading 16 color-palettes, so we increased the colors)

Open now the AdvancePaletteEditor (APE) and load your ROM in it.
Once again search for 0x20 (32) bytes of free space.
Write down the found offset and enter it here:


Now click on "Load". You should see only FFFF's.


Right below, there is another group-box where we can change the palette!
Click on that blue-arrow thingy and choose your previously saved Irfanview-Palette.


Finally, make a click on "Replace" and your done with the palette!
Close the AdvancePaletteEditor and head over to the next step.. ^.^

Editing the ASM

As I said before, we don't need to change the Removing routine, as it only needs
RAM-offsets for calculation. But we need to edit the "Loading.asm".
If you haven't downloaded it yet, now you can.

Ok, if you never touched ASM or anything you will understand nothing, really.
But don't worry, I will explain everything.^^
Open Loading.asm with notepad.

Do you see the many .equ's at the beginning? They define the needed offsets for
the calculation. As you can see, 2 offsets are yet undefined.
".equ IMAGE, 0x08[ROM_OFFSET]" and
".equ PALETTE, 0x08[ROM_OFFSET]"

Exactly, where it says [ROM_OFFSET] we need to insert our image and palette offset!
(I hope you have written them down...)
In my case, my image offset was 0xB50000 and my palette was at 0xB60000.
So after I replaced "[ROM_OFFSET]" with the proper values, my .equ's look like this:

.equ IMAGE, 0x08B50000
.equ DEST, 0x06014C00
.equ PALETTE, 0x08B60000
.equ BUFFER, 0x020379D8
.equ CREATEOAM, 0x08006F8D
.equ IRAM, 0x03000300
Thats part 1/2 of things we have to change ;)
Now search for ~100 bytes of free space in the FreeSpaceFinder.
In my case, I use 0x950000.
This will get the location of your ASM code.
But we need this offset for another thing: Scroll down and look for yourself..

.align 2
.hword 0x2
.hword 0x1
There are several brackets again!
Now we have to replace this brackets with our location of the ASM code
which you found with the FreeSpaceFinder. (0x950000 in my case)

.align 2
.hword 0x2
.hword 0x1
.word OAMDATA + 0x08950000
.word ANIMATION + 0x08950000
After you have replaced all the brackets "[OFFSET_OF_CODE]" save the file
and exit the notepad.

Now go to Desktop and to your thumb folder where as.exe, objcopy.exe and thumb.bat is.
Simply drag the "Loading.asm" into thumb.bat and wait until it has assemblied.


Now you should see another file, "Loading.bin".
Before we touch this file, do the same we did before with the Removing.asm.
Drag the Removing.asm into thumb.bat and Removing.bin should be created.

Open now a Hex-Editor (I use HxD because I like it :D)
Open your ROM, the "Loading.bin" and "Removing.bin".

Go to the offset, where you have searched free space for the ASM code.
(It was 0x950000 in my case)


Now tab over to Loading.bin first.
You should see exactly 0x74 bytes.
Mark the whole bytes by pressing CTRL + A.

Tab over to your ROM again and insert the bytes at your offset (950000 is mine..)
But ATTENTION! Don't simply make CTRL + V at this offset!!
First mark 0x74 bytes at your offset!


And now you can press CTRL + V.


As you can see, for me, at 950074 there is free space again.
And at this position I will insert the Removing.bin, which is 0x28 bytes long.


Finally done with the ASM!
But before I close the HxD, I better write down both of my ASM-offsets:

Loading = 0x950000
Removing = 0x950074
(Yours might be different (from the FSF) so don't use them if yours are different!)

Oke, now I have both offsets of my routines and now?
Now we're going to create a XSE-script.

For testing, we use this simple script:

#dynamic 0x800000
#org @startscript
callasm 0x950001
msgbox @text 0x6
callasm 0x950075

#org @text
= Mugshots rock!
What I forgot to say was that we must add +1 to our ASM offsets!
Don't ask why, just do it.
So that makes 0x950001 and 0x950075 in my case.

Compile the script, copy the offset and give this offset a NPC via AdvanceMap!
Let's test the stuff in VBA!


Oh neat! It works!
Check out the OAM-viewer of VBA btw:


You may not understood what we've done here, but you musn't.
Just enjoy the mugshot ^.^


Well, I hope you like this tutorial, if you have requests, questions or problems, just ask!
But please don't ask me via VM or PM, ask in this thread. I will check it out daily and help.

And yes, dear RSE users, I must find out the OAM-routines of RSE yet.
I will be finished within a week or something, so don't worry
The moderators may change the thread title then (like adding [UPDATE] behind the thread)

OK that's all. Thanks for reading and have fun with this little hack.

And dont forget to give credits as you use source code here!


Unprofessional Unprofessional

Seen 14 Hours Ago
Posted 3 Days Ago
1,745 posts
12.4 Years
This is pretty good stuff here! Good work.
I only glanced over just now, but I didn't see anything about a table or anything.
How would you do multiple mugshots? Using a table that could be read would be easy, but if you had to reinsert the ASM routine every time, that's just troublesome.
Also, say you want a mugshot on the right side of the screen?
Just want some clarifications.
3DS Friend Code: 5069-3944-3902
IGN: Peter; (X, Y, OR, AS, S, M)
Friend Safari: (Fighting) Throh, Meditite, Breloom
Living Pokedex Complete: Y, C, R, LG, E, D, Pl, HG, B, B2, X, Y, OR, AS, M, UM
Big thanks especially to DestinedJagold, Xerneas_X, Elements1 and ~RNC~

PM me if you want to trade, or add my FC.



Seen February 26th, 2014
Posted February 26th, 2014
63 posts
6.1 Years
I could make the code use a table by using a variable that the player has to set before
the callasm (setvar 0xXXXX 0xY or something) but that would be a little more complicated ;)
I will see what I can do, though I can't fulfill every single wish :P

Also, say you want a mugshot on the right side of the screen?
Change this part:

ldr r0, DATA
mov r1, #0x30
mov r2, #0x53
mov r3, #0x0
mov r1, #0x30 is the X-koordinate of the object.
Change it to #0x88 to make it appear on the right side ^.^

To display multiple mugshots, you can call the routine 2 times, but with different koordinates.
The problem with that one is, that both mugshots use the same palette.
To change this, you must call the OAM Buffer and change some things there..
I will for sure update this tut for your wishes :)


Ok guys, table reading and multiple sprite showing works now!
You can now have up to 255 mugshot entries and you can show a maximum of 2 mugshots.

This evening I will post an update on the tutorial!

Seen 1 Day Ago
Posted 4 Weeks Ago
211 posts
7.3 Years
a suggestion?
in my hack for mughsot use a different method.
I made a table of the mugshot and a table for the palette and the load two mugshot in BG0.

ldr r0, .800D // var 800d
ldrh r0,[r0] //save in r0
ldr r1,.800 //load 800 byte (a byte for image 64x64)
mul r1,r0 //multiplicate var 800d * 800
ldr r2, off_table //table in the rom in my case 08A00000
add r0, r2, r1 //add 08A00000 + result of multiplacation
ldr r1,tile //load in tile of BG0 06008000
ldr r2,.400 //lenght to copy/2
swi 0xb

i'm not expert but you and your tutorial are amazing :D good job.



Seen February 26th, 2014
Posted February 26th, 2014
63 posts
6.1 Years
The problem is, that the usage of showpokepic seems not to work in FR.
(you are using ruby, right?)
Thats why i have to use the object-way ;)

My idea of a table is this:

.equ VAR, 0x020370B8

push {r0-r7, lr}
ldr r3, =VAR
ldrb r0, [r3]
mov r2, #0x8
mul r0, r0, r2
ldr r1, =TABLE
add r1, r1, r0
mov r5, r1
ldr r0, [r1]
swi 0x12
In the script, you can set a variable (in my case 0x8000) for the sprite slot you want to use.
Then it calculates (from the table) where the pointers of the images are.
Then I load this pointer into R0 (= destination offset of SWI 0x12) and yeah..

Later in my code, it reads right behind the image pointer the palette pointer.
So my table looks like:

The Stalker

Among the Shadows
Seen November 20th, 2014
Posted June 20th, 2014
16 posts
6 Years
Nice work! This was once thought impossible on FireRed, but I guess with enough ASM knowledge, the boundaries for creativity is far lengthened. I wish I knew how to write ASM routines. Only problem I see is how the head is sort of cut-off, making it look rather weird.
But anyways, I'll give this tutorial a shot when I can find time :3


(☞゚ヮ゚)☞ ☜(゚ヮ゚☜)

Age 21
Seen December 9th, 2016
Posted December 5th, 2016
2,473 posts
7.2 Years
Hey. I have another method that takes a LOT less space but only supports one at a time. Maybe I can post it and you look through it?
I believe in Jesus Christ my Savior. If you do too, and aren't scared to admit it, then copy and paste this into your signature.
The HGSS Music Patch - The BW/2 Music Patch - ASM: Switch Music Based on Seasons Profile - Pokecommunity Profile - Youtube Channel

Support me at my site!
Pokémon Platinum Red and Blue



Seen February 26th, 2014
Posted February 26th, 2014
63 posts
6.1 Years
There are more possibilities which you can do yourself, without knowing ASM.

- Make a kind of direct speech and write "Name:" that we know whos speaking
- Let the one image appear when the one is speaking, let the other appear when
the other person is speaking.
setvar 0x4500 0xSpriteNumber
setvar 0x4501 0x0
setvar 0x4502 0x0
callasm 0xLoad
msgbox @text 0x6
callasm 0xRemove
setvar 0x4500 0xSpriteNumber2
setvar 0x4501 0x1
setvar 0x4502 0x0                     'keep in mind that the sprite slot is now again 0x0
callasm 0xLoad                          'because we removed the other sprite earlier
msgbox @text 0x6
callasm 0xRemove

- Make a darker palette for each sprite and load them how you need it currently

I will see if I can improve this though..



Seen February 26th, 2014
Posted February 26th, 2014
63 posts
6.1 Years
I think it doesn't work with FR. Mugshots dont show, help me, please!
Well it should work ONLY with FR ;)
Tell me exactly what happens.
Open in VBA -> Tools -> OAM viewer
VBA -> Tools -> Memory viewer (Offset 0x7000000)

Send me a screen of both and share your modified ASM code.
Seen 2 Days Ago
Posted June 17th, 2018
37 posts
7.1 Years
I got a pokemon font 64x64 in rom.
Offset loading: 0x29f774
Offset Remove: 0x294890
Script XSE:
#Dynamic 0x800000

#Org @Start
setvar 0x4500 0x0
setvar 0x4501 0x0
setvar 0x4502 0x0
callasm 0x29f775
msgbox @string 0x6
callasm 0x294891

#org @string
= ...


-I do all step, but not show!


Age 22
Seen 1 Week Ago
Posted December 15th, 2019
3,829 posts
9.8 Years
THIS IS AMAZING!But i canot understand why the sprite must be 64x64,if someone wants the sprite bigger ex. 128x128?
It's because the OAM limits sprites to being no bigger than 64 x 64.
What are you so afraid of?
Advertiser Content