PDA

View Full Version : [Tutorial] GBA ASM Programming


Shiny Quagsire
October 2nd, 2010, 07:39 AM
[css-div=border:6px double green;background:url('http://i52.tinypic.com/vxnuoo.png') repeat; size:90%;color:#FFF;][css-div="text-align:center;margin:2px;padding:2px;"]
[css-div=text-align: center]
[css-div=text-shadow:black 2px 2px 2px]
GBA ASM Programming
From scratch and on Pokemon Games
[/css-div][/css-div][/css-div]
[css-div=text-align: left]

Introduction
[css-div=background:rgba(0,0,0,.2);width:98%;border:1px solid #CDAD00;]
If you've ever had to learn about computers, most people say: "The computer uses 0's and 1's," and "Programmers write applications all in 0's an 1's." That's only partially true. Machine code usually is written in C/C++, which is then compiled to Assembly Code, and then 1's and 0's.
[/css-div]
What is Assembly Language
[css-div=background:rgba(0,0,0,.2);width:98%;border:1px solid #CDAD00;]
ASM is a low-level language that (When compiled) processors use to interpret instructions. Here's how Wikipedia defines it:
[css-div=text-align:center;]
[css-div=size:50%;border:1px solid black;padding:8px 8px 8px 8px;margin:8px 8px 8px 8px;background:white;color:black;]
Assembly language is a low-level programming language (http://en.wikipedia.org/wiki/Low-level_programming_language) for computers, microprocessors, microcontrollers, and other integrated circuits. It implements a symbolic representation of the binary machine codes and other constants needed to program a given CPU architecture. This representation is usually defined by the hardware manufacturer, and is based on mnemonics that symbolize processing steps (instructions), processor registers, memory locations, and other language features. An assembly language is thus specific to a certain physical (or virtual) computer architecture.
[/css-div]
[/css-div]

The processor and ASM language the GBA uses is ARM 7, (which is a lot easier compared to Z80, the GBC processor, in my opinion). When you write ASM, All you can do is Add, Subtract, Multiply, load data, and store data. There is no magical "Change the name" command.

You may have noticed there is no divide. The problem is that there are no decimals in ARM 7 ASM, and division is generally harder on the processor to calculate. There are BIOS functions to divide, but there are some tricks to doing simple dividing that I'll explain later.
[/css-div]

What We'll need:
[css-div=background:rgba(0,0,0,.2);width:98%;border:1px solid #CDAD00;]

VisualBoyAdvance
A compiler - To put our ASM into Hex
VBA-SDL-H - For testing, or debugging, our ASM to see how it works or to find problems.
A Brain XD

[/css-div]

Let Me Try! Let Me Try!
[css-div=background:rgba(0,0,0,.2);width:98%;border:1px solid #CDAD00;]
I think the best way of learning is to let you see what you can do with this knowledge. So, first, download my ASM Pack (http://dl.dropbox.com/u/22473948/TutorialPack.7z), which includes:


A compiler
HackMew's Nifty Batch File - Thanks HackMew!
Some ASM Code


With that downloaded and extracted, go into the command prompt. After all, the assembler is command prompt based.
[css-div=size:50%;border:1px solid black;padding:8px 8px 8px 8px;margin:8px 8px 8px 8px;background:white;color:black;]
If you don't know how to use the command prompt, just google 'Command Prompt Tutorials.' You'll find something ;)
[/css-div]
When you open it, you'll see somthing similar to this:

[css-div=background-image:url('http://mtinc.webs.com/consoleimage.bmp');color:rbg(192,192,192);font-family:lucida console;size:auto;padding:33px 7px 6px 6px;margin-left:20px;background-repeat:no-repeat;min-height:300px;]
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\XXXXXX>
[/css-div]

Now, navigate to the directory you placed it in. For me, it's in a folder on my desktop called ASM. Try to keep folder names short, and simple.
[css-div=background-image:url('http://mtinc.webs.com/consoleimage.bmp');color:rbg(192,192,192);font-family:lucida console;size:auto;padding:33px 7px 6px 6px;margin-left:20px;background-repeat:no-repeat;min-height:300px;]
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Maxamillion>cd Desktop\ASM\tutorial
[/css-div]
Now we need to assemble it, so type in this:

thumb example1.asm example1.bin


Here's our output:
[css-div=background-image:url('http://mtinc.webs.com/consoleimage.bmp');color:rbg(192,192,192);font-family:lucida console;size:auto;padding:33px 7px 6px 6px;margin-left:20px;background-repeat:no-repeat;min-height:300px;]
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Thomas>cd Desktop\ASM\tutorial
C:\Documents and Settings\Thomas\Desktop\ASM\tutorial>thumb example1.asm example1.bin
Assembled successfully.
Press any key to continue . . .
[/css-div]

Obviously press any key, and we're done!
[/css-div]

What a Piece of Junk!
[css-div=background:rgba(0,0,0,.2);width:98%;border:1px solid #CDAD00;]
OK, so we assembled our routine, but how do we use it?! First, open up our example1.bin we assembled into a hex editor. You should get something like this:

[css-div=background-color: #FFF; color: #000; font-family: Lucida Console; width: 600px; padding: 8px 8px 8px 8px; word-spacing:3px;"]
03 B5 02 48 80 88 02 49 08 80 03 BD 84 42 02 02 D0 70 03 02
[/css-div]

Now, open your Pokemon ROM into a hex editor, and copy it to a free-space address ending with 0, 4, 8, or C. You may ask, "Why not 5? or 7?" Because these numbers aren't multiples of four, and it uses bit 0, a bit used to tell the game "Do you want to boot into Thumb or ARM?" So, once you have it copied, you'll need to set bit 0 to 1, or, simply put, add 1 to your offset. So if I placed it at 0x720000, I'd add 1, making it 0x720001.

With this inserted, how do we use it through a script? (Please note this is an ASM tutorial, and no questions regarding scripting will be answered, unless it's a problem with booting the ASM in the script.) The answer is simple. We use the magical callasm command. So, here's an example script to use, since you don't know how the ASM works yet.

[css-div=background-color: #FFF; color: #000; font-family: Lucida Console; width: 600px; padding: 8px 8px 8px 8px;"]
#dynamic 0x800000

#org @start
lock
faceplayer
callasm 0xsomeoffset
buffernumber 0x0 lastresult
msgbox @msg 0x2
release
end

#org @msg
= Wow, your POKEMON is at level !
[/css-div]

Once that's inserted, go ahead and go to VisualBoyAdvance and open your script. Here's what your result should look like:
http://i53.tinypic.com/ddj5za.png

But was that it's level? Let's check!
http://i52.tinypic.com/v7uqf9.png

There it is! But how'd the ASM return it? That will be explained in the next section.
[/css-div]

Looking? Found someone you have, eh?
~Yoda
[css-div=background:rgba(0,0,0,.2);width:98%;border:1px solid #CDAD00;]
Alright, so we've had some fun, but we've never seen what's going on in the ASM, or the script. Now let's see how it works by looking at Pokemon data, then explain each command one by one in the ASM routine.

Pokemon Data
The Pokemon data can be explained in detail here (http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_in_Generation_III). You can check it out to see where some things are. The stats and such don't start untill about byte 80.
The byte we are retrieving, is the level, 1 byte with a maximum of 256. Let's see how we load those bytes by opening the ASM file according to your game. They'll all be slightly different, but they all have the same commands at a glance.

.align 2
This aligns the ASM by a multiple of 2, since each instruction is 2 bytes long.

.thumb
This tells the assembler that we are using the thumb instruction set. If we were using ARM, we'd use .ARM

main:
This is label. Labels are ways to call parts of a routine without calculations or repeating things over and over. Labels are text (Without spaces), and end with a colon. This label is called "main"

push {r0-r1,lr}
This pushes registers r0, r1, and the link register into the stack.

Registers are like variables that store temporary values and information. Registers are 32 bits long, making the highest value possible FFFFFFFF.
The stack is a bit hard to explain. Think of 15 stacks of china plates. Each of them has a different design on them. When you push a register into the stack, it's like adding a new plate as the one on the top to the stack. Here's a visual representation from Wikipedia:
http://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Data_stack.svg/391px-Data_stack.svg.png
The Link Register tells the processor where to return from the parent routine that called this one.

ldr r0, pokemon_data
This loads a 32 bits at the label 'pokemon_data' into r0. These bits, or bytes contain the address to our party data.

ldrh r0, [r0]
Loads a 'half-word,' or 16 bits, (or 2 bytes) from the address at r0.

ldr r1, var
This loads the data at the label var, which is the location of LASTRESULT in the WRAM. (Work RAM)

strh r0, [r1]
This stores the half-word in r0 at the address in r1. But r0 has a byte, not a half-word! It stores a half-word, not because r0 has a half word, but variables are only 1 half-word long.

pop {r0-r1,pc}
This 'pops,' or removes the registers r0, r1, and pc from the top of the stack, leaving the original registers again. You may ask "Why not pop {r0-r1, lr}? Well, pc is our current position. When we pop this, It continues onto where it was before. The link register will reset by itself. Here's the image again to help explain:
http://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Data_stack.svg/391px-Data_stack.svg.png

.align 2
We need to make sure our variables are multiples of two, so the routine can access them.

pokemon_data:
Another label, giving our Pokemon data.

.word 0x02024284 + 0x54
Writes the word 0x02024284 + 0x54 at this spot.

var:
A label for our variable.

.word 0x020270B6 + (0x800D * 2)
The offset of the first variable plus 0x800D, the lastresult variable, x 2, since variables are 2 bytes long.
[/css-div]


Returning Values at the Bit Level
[css-div=background:rgba(0,0,0,.2);width:98%;border:1px solid #CDAD00;]
Alright, we've checked code, we've disected code, now lets go even deeper into pokemon values!

[b]What New Commands We'll need:
lsl rX, #0xV - This shifts the bits in rX left byte 0xV positions.
lsr rX, #0xV - This does the same as above, but shifts bits right.
ldrb rX, [rY, #0xV] - Loads a byte from the address at rY + 0xV into rX. The 0xV is optional though.
There are also other methods that you can use, and it's usually the same with all ldr commands.
ldrb rX, label - Loads a byte from a label.

What we'll be doing
I decided to make a tutorial with something to the bit level. After all, bits are hard to manipulate at first, but it's key to disecting some things.

Status Conditions
Status conditions are based on bits. Here's a quote from bulbapedia:

Status ailment
The Pokémon's status ailments are stored as follows:

0-2: Sleep bits. Indicates turns of sleep, so 111b = 7 turns, 101b = 5 turns, etc.
3: Poison
4: Burned
5: Frozen
6: Paralysis
7: Bad poison


Now, let's see how we can get, say, the sleeping bit perhaps. Let's write some code!

Down and Dirty!
Alright, lets get to work. First, create a brand new txt file, and rename it Status_[gameprefix].asm the game prefix should be like my example1_fr, or example1_rs. Try to keep names without spaces, and short and sweet.

Now, add this to the top of your file:

.align 2
.thumb

main:
push {r0-r1,lr}
ldr r0, pokemon_data

That is the start of our first code, but we need to load a byte at 80 bytes afterwards, or 0x50 bytes.

ldrb r0, [r0]

Now, lets say we wanted to get the sleeping bits. We'd have to shift everything over left by 5 spaces,leafing the three sleeping bits. And since it has the number of turns asleep, that could be what we return!

lsl r0, #0x5
lsr r0, #0x5

What this does is takes a value like:
10101010
turns it into this:
01000000
Then this:
010
Which is the sleep value!
And now we write it to the variable 0x800D

ldr r1, var
strh r0, [r1]
pop {r0-r1,pc}

Now, take the bottom labels starting at the second .align 2 from the previous code file. Also, add "+ 0x50" to the end of pokemon_data.
For example, I'd add this:


.align 2

pokemon_data:
.word 0x02024284 + 0x50
var:
.word 0x020270B6 + (0x800D * 2)

Alright, lets give it a test run! Go ahead and compile it with thumb.bat. Here's an example script we can use.

#dynamic 0x800000

#org @start
lock
faceplayer
callasm 0xyouroffset
buffernumber 0x0 lastresult
msgbox @msg 0x2
release
end

#org @msg
= That POKEMON sure is sleepy.\nIt's going to sleep [buffer1] turns!

Now attach that script to someone, and lets go!

http://i56.tinypic.com/282wro.png

Of course, my pokemon wasn't asleep, but it returned the value. Feel free to debug it if you want!

The Challenge of the Day!
Can you return the value of a burn? Perhaps poison? Return your ASM with an image!
[/css-div]

Value Changing, Comparing, and Arithmetic Commands
[css-div=background:rgba(0,0,0,.2);width:98%;border:1px solid #CDAD00;]
In this tutorial, we're going to cover commands used to change value, compare, and do arithmetic functions, which are some of the most essential commands (In my opinion) to ARM7 ASM.

New Commands used in this Section:
mov rX, #0xY Moves the value in rX to 0xY.
add rX, rY, rZ Adds the contents of rY and rZ and places it on rX.
add rX, #0xY Adds 0xY to rX.
sub rX, rY, #0xZ Subtracts 0xZ from rY and places it on rX. It generally has the same syntax as adding.
mul rX, rY, rZ Multiplies rY and rZ and places the result on rX. rZ cannot be replaced with a hex number like #0x5.
cmp rX, #0xY Compares the value in rX to 0xY and stores the results to the flags. 0xY can also be a register.
teq rX, #0xY This is sort of a limited cmp command, that tests if rX is equal to 0xY.
b{condition} label Compares the flags depending on the condition, and if the result meets the condition, the processor goes to label.

Using Comparing Commands
Comparing commands work by subtracting 0xY from rX, and placing the results in the flags. It doesn't really return any result to a register. Here's a quote from ARM's website:

These instructions compare the value in a register with Operand2. They update the condition flags on the result, but do not place the result in any register.

The CMP instruction subtracts the value of Operand2 from the value in Rn. This is the same as a SUBS instruction, except that the result is discarded.

So, that's how it works. Unfortunatly, the flags are protected from access in thumb mode, but there is a command that can do it for us. It's the command "b".

http://t1.gstatic.com/images?q=tbn:ANd9GcRGgQ4A2_nvlZjtVrhFWO8SDNqMH73knTNJT9gGMqpMRs1wwfc&t=1&usg=__wVXr1CdfZ7HazbJyuifwRkvMlgw=

How 'b' works is it compares the flags to a condition. If it is met, it goes to another label. The conditions are as follows:

EQ Equal
NE Not equal
CS/HS Higher or same (unsigned >= )
CC/LO Lower (unsigned < )
MI Negative
PL Positive or zero
VS Overflow
VC No overflow
HI Higher (unsigned <= )
LS Lower or same (unsigned <= )
GE Signed >=
LT Signed <
GT Signed >
LE Signed <=
AL Always (usually omitted, same as just "b" by itself.)

So bhi rX, rY would be like this equasion:

rX <= rY

If the equasion is true, it goes to the label. If not, it continues.

A Quick Example
For this, we won't have an active code sample that does something, simple because this is more for learning the commands. Instead, lets have some examples:

.align 2
.thumb

main:
push {r0-r1}
mov r0, #0x5 @Moves r0 to 5
sub r0, #0x3 @Subtracts 3 from r0
mov r1, #0x3 @Move r1 to 3
mul r0, r1, r0 @multiplies r0 and r1, and places the result on r0
cmp r0, #0x6 @Compares r0 to 6, which it should be
beq end @If equal goes to the label 'end'
end:
pop {r0-r1}


And that pretty much covers everything we need!
[/css-div]

[/css-div]
[/css-div]

Orinjmate
October 2nd, 2010, 12:36 PM
Wow FINALLY someone has put up a tut on ASM! This should be useful to alot of people. Can you write an ASM script on a free space offset then in XSE use 'callasm 0xoffset' to make it run in the middle of the script?

Random92
October 2nd, 2010, 01:09 PM
This tutorial seems nice.

Could you just give me a few reasons why I need ASM. What can I do with it that I can't do with the normal tools out there, a-map, xse etc.

Spherical Ice
October 2nd, 2010, 01:48 PM
You can do essentially anything with ASM, within the GBA limitations of course, if you know how to. ASM stands for assembly - what builds up the game.

Anyway, nice tutorial. I've only skimmed it, but I'll read it properly later.

Shiny Quagsire
October 2nd, 2010, 02:44 PM
This tutorial seems nice.

Could you just give me a few reasons why I need ASM. What can I do with it that I can't do with the normal tools out there, a-map, xse etc.

You can pretty much do anything that's in another gba game. Your only limit is your imagination the gba's ram.

miksy91
October 2nd, 2010, 10:47 PM
I had hard time understanding all those commands you used.
ldr r1, var
strh r0, [r1]
pop {r0-r1,pc}

Anyway, this tutorial was really worth reading :)

TB Pro
October 2nd, 2010, 11:35 PM
I had hard time understanding all those commands you used.
ldr r1, var
strh r0, [r1]
pop {r0-r1,pc}

Anyway, this tutorial was really worth reading :)
ldr loads var into the specified register, here it is r1.
strh stores a half-word at r0 into r1.
pop just pops them all back, you pushed, now you have to pop.

chriskid198
October 3rd, 2010, 11:46 PM
I'm wondering what types of scripting there is?

The type of scripting I use is very similar to this,

#dynamic 0x800000

#org @start
lock
faceplayer
callasm 0xyouroffset
buffernumber 0x0 lastresult
msgbox @msg 0x2
release
end

#org @msg
= That POKEMON sure is sleepy.\nIt's going to sleep [buffer1] turns!

Would be a script that I would use.

Shiny Quagsire
October 4th, 2010, 06:59 PM
I'm wondering what types of scripting there is?

The type of scripting I use is very similar to this,

#dynamic 0x800000

#org @start
lock
faceplayer
callasm 0xyouroffset
buffernumber 0x0 lastresult
msgbox @msg 0x2
release
end

#org @msg
= That POKEMON sure is sleepy.\nIt's going to sleep [buffer1] turns!

Would be a script that I would use.

pretty much, just replace youroffset woth the offset of your ASM + 1.

Lodestar
October 4th, 2010, 09:43 PM
I'm a little confused about something. You said "Registers are 32 bits long, making the highest value possible FFFFFFFF." but your code shifts the status back and forth by only 5 bits. Wouldn't that return the same number? Don't you need to shift by 0x1d?

I dunno, bit shifting wasn't covered by my intro to programming course. I learned it on my own so I'm probably wrong.

HackMew
October 5th, 2010, 02:22 AM
If you've ever had to learn about computers, most people say: "The computer uses 0's and 1's," and "Programmers write applications all in 0's an 1's." That's only partially true. Machine code usually is written in Assembly Language.

Programmers don't write applications in binary. Since human beings are smart enough, however, they invented assembly, a language with human-friendly instructions that could get assembled into machine code, a CPU-friendly format.

ASM is a low-level language that processors use to interpret instructions.

CPUs are not ASM interpreters. In fact, they cannot understand ASM. You have to assemble your routines into machine code before they actually get working.

The processor and ASM language the GBA uses is ARM 7, which is a lot easier compared to Z80, the GBC processor.

On what assumptions?

You may have noticed there is no divide. The problem is that there are no decimals in ARM 7 ASM.

You know, there's still integer division.

#org @msg
= Hey, that Pokemon's ID is !

That's not the Pokémon's ID. That's the Pokémon Original Trainer (OT) ID.

Now, open your Pokemon ROM into a hex editor, and copy it to a free-space address ending with 0, 4, 8, or C. You may ask, "Why not 5? or 7?" Because these numbers aren't multiples of four, and it uses bit 0, a bit used to tell the game "Do you want to boot into Thumb or ARM?"

No, that's not the reason. You have to use a 4-byte offset for literal pools, so that they're properly aligned. Theoretically, if you don't have a literal pool, you would just need a 2-byte aligned offset (almost all THUMB instructions take 2 bytes, indeed).

[b]Registers are like variables that store temporary values and information. Registers are 32 bits long, making the highest value possible FFFFFFFF.

Not necessarily. 0xFFFFFFFF is the highest, unsigned value. The highest signed value would be 0x7FFFFFFF.

Think of 15 stacks of china plates. Each of them has a different design on them.

Why would the plates be different?

ldr r0, pokemon_data
This loads a 32 bits at the label 'pokemon_data' into r0. These bits, or bytes contain the address to our party data.

ldr r1, var
This loads the data at the label var, which is the location of LASTRESULT in the WRAM. (Work RAM)


"pokemon_data" and "var" are not a label. They're symbols.

strh r0, [r1]
This stores the half-word in r0 at the address in r1. But r0 has a byte, not a half-word!

Actually r0 has 32 bits, or 4 bytes.

The link register will reset by itself.

It won't.

.word 0x020270B6 + (0x800D * 2)
The offset of the first variable plus 0x800D, the lastresult variable, x 2, since variables are 2 bytes long.

0x020270B6 is not the address of the first variable. Especially considering FR/LG are DMA-based and the address changes from time to time. No, 0x020270B6 is just a fictitious address I came up with to makes things easier to read.

Wow FINALLY someone has put up a tut on ASM! This should be useful to alot of people. Can you write an ASM script on a free space offset then in XSE use 'callasm 0xoffset' to make it run in the middle of the script?

What about the search function? I first published my ASM tutorial on February 14th, 2009.

You can pretty much do anything that's in another gba game. Your only limit is your imagination the gba's ram.

GBA RAM might be enough. But there are technical limits too.
Fix your spelling mistakes, and the smilies. Also, learn before teaching.

strh stores a half-word at r0 into r1.

Into the address which r1 is currently holding.

I'm a little confused about something. You said "Registers are 32 bits long, making the highest value possible FFFFFFFF." but your code shifts the status back and forth by only 5 bits. Wouldn't that return the same number? Don't you need to shift by 0x1d?

I dunno, bit shifting wasn't covered by my intro to programming course. I learned it on my own so I'm probably wrong.

Nice to see someone else noticed. Yeah, the code shiny quagsire posted is wrong. The sleep turns are the lowest 3 bits. So you do:


lsl r0, r0, #0x1D
lsr r0, r0, #0x1D

In other words, you shifts the status value by 0x1D bits (thus clearing all the bits except the sleep ones), and then you shift it back.

Shiny Quagsire
October 5th, 2010, 02:42 PM
OMG!!! YOU HAVE BEEN PWNED!!!

That's spam, and it's plain rude :(

Programmers don't write applications in binary. Since human beings are smart enough, however, they invented assembly, a language with human-friendly instructions that could get assembled into machine code, a CPU-friendly format.

You failed to read the rest.
That's only partially true. Machine code usually is written in Assembly Language.
[/QUOTE]


CPUs are not ASM interpreters. In fact, they cannot understand ASM. You have to assemble your routines into machine code before they actually get working.

I'm aware. Thanks for clarification.


On what assumptions?


Alright, fine. Be that way. It's just an opinion based on the Z80 I've seen.


You know, there's still integer division.

I was stating there is no command for it. And you failed to read the rest (Again...)

However, there are some tricks to dividing I'll explain later.



That's not the Pokémon's ID. That's the Pokémon Original Trainer (OT) ID.

And that's an old script waiting to be replaced.


No, that's not the reason. You have to use a 4-byte offset for literal pools, so that they're properly aligned. Theorically, if you don't have a literal pool, you would just need a 2-byte aligned offset (almost all THUMB instructions take 2 bytes, indeed).

We learn something new every day. :D I thought I read that somewhere, or maybe my mind was fooling be :p


Not necessarily. 0xFFFFFFFF is the highest, unsigned value. The highest signed value would be 0x7FFFFFFF.


It's the highest possible value whether unsigned or signed is it not?


Why would the plates be different?


It's like items on a menu. They aren't all just a different name with the same things. The plate's design represents how the values are different.


"pokemon_data" and "var" are not a label. They're symbols.


Here's a quote:

Also, that Start: right there is marking the beginning of the code. It’s not just an annotation like commentaries. That is a label. These are the name of the address of that instruction (the name we gave it, that is). While compiling, any instructions that make a reference to a label will be replaced with its respective address relative to its position. More on that when we talk about jumps.



Actually r0 has 32 bits, or 4 bytes.
If r0 has 000000ff, it would be a byte no? It contains a value equivalent to a byte, or if we want to, a half word.


It won't.

OK.


0x020270B6 is not the address of the first variable. Especially considering FR/LG are DMA-based and the address changes from time to time. No, 0x020270B6 is just a fictitious address I came up with to makes things easier to read.

OK, fine.



GBA RAM might be enough. But there are technical limits too.
Fix your spelling mistakes, and the smilies. Also, learn before teaching.


What mistakes? And I know my coding, just not extremely technical areas.


Into the address which r1 is currently holding.


That's what I meant.


Nice to see someone else noticed. Yeah, the code shiny quagsire posted is wrong. The sleep turns are the lowest 3 bits. So you do:


lsl r0, r0, #0x1D
lsr r0, r0, #0x1D

In other words, you shifts the status value by 0x1D bits (thus clearing all the bits except the sleep ones), and then you shift it back.

Wait, hows that work? If we load and shift left 0x1d, that would wipe out the byte. Or am I wrong again?

NarutoActor
October 5th, 2010, 05:35 PM
I think the problem with your plate analogy, is that the plates can have the same value.(or same design)
Also, do I sense jealousy from the great hack mew. :O

P.S. You left a quote bracket open. Always re-read your work before posting, and if there are brackets, utilize the preview post.

Lodestar
October 5th, 2010, 10:17 PM
If r0 has 000000ff, it would be a byte no? It contains a value equivalent to a byte, or if we want to, a half word.

It's still a 32-bit variable. Even if you only use the first 8 bits, it's still has the other 24 bits.

What mistakes? And I know my coding, just not extremely technical areas.

The file name paths are getting replaced with that one smily. :\ <- that one

Wait, hows that work? If we load and shift left 0x1d, that would wipe out the byte. Or am I wrong again?

Form what I can tell, it would wipe out everything except the last three bits. And Bulbapedia says those last three are the sleep bits. So that's what you want.

chriskid198
October 5th, 2010, 11:06 PM
pretty much, just replace youroffset woth the offset of your ASM + 1.Okay, so I can use this for XSE?

TB Pro
October 6th, 2010, 04:08 AM
Okay, so I can use this for XSE?
The script, yes. You still have to write your routine in notepad and assemble it.

chriskid198
October 6th, 2010, 10:42 PM
The script, yes. You still have to write your routine in notepad and assemble it.Routine?

*Looks at first post*

Shiny Quagsire
October 7th, 2010, 06:23 AM
The routine is in my hack pack. Without it, the script is useless, and will most likely cause the game to crash.

Anyways, I've added a section on the core commands like arithmatic, branching, and other things like that.

TB Pro
October 7th, 2010, 06:21 PM
Routine?

*Looks at first post*
The routine is all the ASM *stuff* that you write down.

this is a routine:

.text
.align 2
.thumb
.thumb_func
.global testz

main:
push {r0-r1}
mov r0, #0x5
sub r0, #0x3
mov r1, #0x3
mul r0, r1, r0
cmp r0, #0x6
beq end
end:
pop {r0-r1}

Shiny Quagsire
October 7th, 2010, 06:56 PM
The routine is all the ASM *stuff* that you write down.

this is a routine:

.text
.align 2
.thumb
.thumb_func
.global testz

main:
push {r0-r1}
mov r0, #0x5
sub r0, #0x3
mov r1, #0x3
mul r0, r1, r0
cmp r0, #0x6
beq end
end:
pop {r0-r1}

Yes, and that routine was to explain the arithmatic commands, and doesn't do anything. Don't try compiling and inserting, because your game will freeze.

TB Pro
October 8th, 2010, 01:39 PM
Yes, and that routine was to explain the arithmatic commands, and doesn't do anything. Don't try compiling and inserting, because your game will freeze.
Yeah I know, I was just trying to explain what a routine was to him.

chriskid198
October 9th, 2010, 07:09 PM
Yeah I know, I was just trying to explain what a routine was to him.And thanks for that..

But I still don't understand how to insert it into the game.. I can't find that link for the package thing.

And one more question, is this basically scripting? Like this (http://www.pokecommunity.com/showthread.php?p=6212940#post6212940).

~Teh Panda~
October 9th, 2010, 07:11 PM
And thanks for that..

But I still don't understand how to insert it into the game.. I can't find that link for the package thing.

And one more question, is this basically scripting? Like this (http://www.pokecommunity.com/showthread.php?p=6212940#post6212940).

Scripting is writing with the games pre-designed system for making in game events, in other words the way that pokemon games can read it, which is way you can't per say script your own game using that sort of scripting.

ASM is essentially working directly with the hardware

chriskid198
October 10th, 2010, 10:36 PM
Scripting is writing with the games pre-designed system for making in game events, in other words the way that pokemon games can read it, which is way you can't per say script your own game using that sort of scripting.

ASM is essentially working directly with the hardwareAh, thanks ~Teh Panda~, do you mine if I call you Panda? :)

So, if you use ASM, you can use stuff thats not in the game? Like specials and stuff?

Shiny Quagsire
October 12th, 2010, 03:20 PM
Ah, thanks ~Teh Panda~, do you mine if I call you Panda? :)

So, if you use ASM, you can use stuff thats not in the game? Like specials and stuff?

Pretty much. You're only limited by the actual hardware and RAM.

Anyways, once I fix my computer's viruses I'm probably going to start writing a new section. It's either going to be on another data access thing or a game from scratch. If you'd like one of the two more, just comment ;)

Full Metal
October 12th, 2010, 05:57 PM
"pokemon_data" and "var" are not a label. They're symbols.


Can you explain the difference between these two?
I thought that (labels/symbols) worked by the assembler calculating the distance between the (symbol/label) and the current instruction (and then doing stuff to make the instruction)
And you branch to a label, but in the end doesn't the assembler do the same sort of thing?
Not arguing, just trying to learn, i promise ^_^;

Shiny Quagsire
October 14th, 2010, 05:43 PM
Can you explain the difference between these two?
I thought that (labels/symbols) worked by the assembler calculating the distance between the (symbol/label) and the current instruction (and then doing stuff to make the instruction)
And you branch to a label, but in the end doesn't the assembler do the same sort of thing?
Not arguing, just trying to learn, i promise ^_^;

Codewise, there isn't really much of a difference. You could use a label or symbol and it really wouldn't matter. However, if your naming a section, I'm not so sure if that's OK.

0m3GA ARS3NAL
November 9th, 2010, 03:13 PM
I like it, though I have a question.

About that sleep bit loading, how can one CHANGE the bits like the sleep bits, to induce sleep?

Shiny Quagsire
November 9th, 2010, 03:41 PM
I like it, though I have a question.

About that sleep bit loading, how can one CHANGE the bits like the sleep bits, to induce sleep?

I've had to set bits, and I've found that the best way to do it is:

Shift the bits right to ensure there isn't any sleep bits already there
Add a number (Let's say, 3) to the amount
Store that value back into the RAM with strb

0m3GA ARS3NAL
November 9th, 2010, 03:49 PM
I've had to set bits, and I've found that the best way to do it is:

Shift the bits right to ensure there isn't any sleep bits already there
Add a number (Let's say, 3) to the amount
Store that value back into the RAM with strb


I'm a little confused...

may I have an example?

Shiny Quagsire
November 9th, 2010, 03:59 PM
I'm a little confused...

may I have an example?

Sure :)

OK, lets take our initial routine:

.align 2
.thumb
.global example1

main:
push {r0-r1,lr}
ldr r0, pokemon_data
ldrb r0, [r0]
lsl r0, r0, #0x5
lsr r0, r0, #0x5
ldr r1, var
strh r0, [r1]
pop {r0-r1,pc}

.align 2

pokemon_data:
.word 0x02024284 + 0x50
var:
.word 0x020270B6 + (0x800D * 2)



Now, we want to replace all of our checking and returning stuff with this:


lsr r0, r0, #0x3 @Shift over initial sleeping bits (If there)
lsl r0, r0, #0x3 @Set it back
add r0, #0xyoursleepturns @Add our number of sleeping turns
ldr r1, pokemon_data @Load our writing destination
strh r0, [r1] @store r0 in the address contained in r1


Our final result:


.align 2
.thumb
.global example1

main:
push {r0-r1,lr}
ldr r0, pokemon_data
ldrb r0, [r0]
lsr r0, r0, #0x3
lsl r0, r0, #0x3
add r0, #0xyoursleepturns
ldr r1, pokemon_data
strh r0, [r1]
pop {r0-r1,pc}

.align 2

pokemon_data:
.word 0x02024284 + 0x50


Since I didn't need the var, I removed it :)

0m3GA ARS3NAL
November 9th, 2010, 05:35 PM
This pleases 0m3GA
Thanks, it makes more sense once I see a commented out routine.

Little ASM hacks like these are pretty easy now that I see it, but the bigger stuff, like Day and Night, and Havking the player's sprite to change it and keep it changed...

2RandomStudios
November 30th, 2010, 10:16 AM
after much trial and error, I simply can't get the thumb.bat to work! it gives me errors such as "as.exe is missing" (which it isnt) and "can't compile example1_fr.asm the file does not exist" (which it does)
Please help!

forestw785
November 30th, 2010, 04:26 PM
after much trial and error, I simply can't get the thumb.bat to work! it gives me errors such as "as.exe is missing" (which it isnt) and "can't compile example1_fr.asm the file does not exist" (which it does)
Please help!

I'm guessing you didn't route your cmd prompt to the folder with your ASM stuff.

If it's on your desktop, then how you route command prompt there would be:
xp: cd \Documents and Settings\(username for your computer)\Desktop\ASM
7/Vista: cd \Users\(username for your computer)\Desktop\ASM

And press enter, and then the command prompt is rerouted to your ASM folder.


My problems:
I follow your tutorial, and I get everything to work in the first two lessons with no problems, but even with your "explanations" I don't understand what these codes are actually doing. I'm basically just telling the ROM to behave a certain way without knowing how I'm making it behave that way.
Example:
What is a callasm?
What is buffernumber 0x0 lastresult

There are others too, and you even define them. An example of that would be:
.align 2-This aligns the ASM by a multiple of 2, since each instruction is 2 bytes long. (aligning the ASM does what exactly?, and a multiple of two what?)
push {r0-r1,lr}- This pushes registers r0, r1, and the link register into the stack. (what is {r0-r1,lr}? what is r0, r1, and lr?}

Look at it from someone else's perspective:
Gita monooto hon : These are words in another language, and they deal with sound.
Not specific enough, and provide no real understanding of the material, right?

2RandomStudios
November 30th, 2010, 08:50 PM
I'm guessing you didn't route your cmd prompt to the folder with your ASM stuff.

If it's on your desktop, then how you route command prompt there would be:
xp: cd \Documents and Settings\(username for your computer)\Desktop\ASM
7/Vista: cd \Users\(username for your computer)\Desktop\ASM

And press enter, and then the command prompt is rerouted to your ASM folder.


My problems:
I follow your tutorial, and I get everything to work in the first two lessons with no problems, but even with your "explanations" I don't understand what these codes are actually doing. I'm basically just telling the ROM to behave a certain way without knowing how I'm making it behave that way.
Example:
What is a callasm?
What is buffernumber 0x0 lastresult

There are others too, and you even define them. An example of that would be:
.align 2-This aligns the ASM by a multiple of 2, since each instruction is 2 bytes long. (aligning the ASM does what exactly?, and a multiple of two what?)
push {r0-r1,lr}- This pushes registers r0, r1, and the link register into the stack. (what is {r0-r1,lr}? what is r0, r1, and lr?}

Look at it from someone else's perspective:
Gita monooto hon : These are words in another language, and they deal with sound.
Not specific enough, and provide no real understanding of the material, right?

I followed that step exactly and it tells me that "C:\Users\(name)\Desktop\ASM" is not a recognized command!

Team Fail
November 30th, 2010, 08:55 PM
I followed that step exactly and it tells me that "C:\Users\(name)\Desktop\ASM" is not a recognized command!

I'm sure if you use CD Desktop, or C:\Users\Name\CD it will work. It will than say C:\Desktop_ and you can continue from there.

colcolstyles
November 30th, 2010, 08:55 PM
I followed that step exactly and it tells me that "C:\Users\(name)\Desktop\ASM" is not a recognized command!

That's probably because you forgot to include the "cd" before the file path. Try this:

cd C:\Users\(name)\Desktop\ASM

Shiny Quagsire
November 30th, 2010, 09:10 PM
I'm guessing you didn't route your cmd prompt to the folder with your ASM stuff.

If it's on your desktop, then how you route command prompt there would be:
xp: cd \Documents and Settings\(username for your computer)\Desktop\ASM
7/Vista: cd \Users\(username for your computer)\Desktop\ASM

And press enter, and then the command prompt is rerouted to your ASM folder.


My problems:
I follow your tutorial, and I get everything to work in the first two lessons with no problems, but even with your "explanations" I don't understand what these codes are actually doing. I'm basically just telling the ROM to behave a certain way without knowing how I'm making it behave that way.
Example:
What is a callasm?
What is buffernumber 0x0 lastresult

There are others too, and you even define them. An example of that would be:
.align 2-This aligns the ASM by a multiple of 2, since each instruction is 2 bytes long. (aligning the ASM does what exactly?, and a multiple of two what?)
push {r0-r1,lr}- This pushes registers r0, r1, and the link register into the stack. (what is {r0-r1,lr}? what is r0, r1, and lr?}

Look at it from someone else's perspective:
Gita monooto hon : These are words in another language, and they deal with sound.
Not specific enough, and provide no real understanding of the material, right?

Alright. It sounds like you havn't done too much scripting. Callasm calls a select routine from a script. It basically calls your ASM and returns. Call ASM. Buffernumber takes a number in a variable and stores it into a buffer such as [buffer1]. As for alignment, it makes sure the labels, and accessed data can are in addresses that are multiples of two.



A Simple Example (http://www.asmcommunity.net/book/Alignment)
Boundaries are evenly divisible memory addresses. For example, an address that is aligned on a 4-BYTE (DWORD) boundary is evenly divisible by 4. The processor will always get it's data from DWORD boundaries and in DWORD sizes. So, if you had the following
1111 2222 3333 4444...
and you wanted to get the second DWORD, the processor would find it on an address divisible by 4 (a boundary) and get it in one fetch. However, if the data was misaligned like this
1122 2233 3344 4400...
and you wanted the same DWORD, the processor would
1. Get the first DWORD (FETCH 1)
2. Chop off the leftmost 3 bytes
3. Get the second DWORD (FETCH 2)
4. Chop off the rightmost 1 byte
5. Then put them both together.
This requires 2 memory fetches and takes longer to execute. This is how it applies to DWORDs as in the previous example. For word size values, there would be no change because the 2 bytes are available in the first pass in both cases. There are certain instructions that work better on 16-BYTE boundaries (such as movsd) and some that require it (some FPU instructions).



So basically it allows code to be acessed right and it helps the processor to be faster.

r0, r1, and lr are your variables. They are used to keep data for code, and then the data is used. Some times they hold addresses, data to be written, and arguments for other routines.

2RandomStudios
November 30th, 2010, 10:18 PM
That's probably because you forgot to include the "cd" before the file path. Try this:

cd C:\Users\(name)\Desktop\ASM

Thanks so much for the help. It works perfectly now!

0m3GA ARS3NAL
November 30th, 2010, 10:50 PM
Thanks so much for the help. It works perfectly now!

Alternativly, you can go to

C:/Windows/System32/

Grab the CMD.exe file there and COPY it, then paste the copy in the folder with the as.exe file.

From then on all you've got to do is double click on the CMD.EXE and then go from there, no need to redirect it.
You can also put a shortcut onto the desktop for easy access.

SPG
January 3rd, 2011, 06:39 PM
quick question, how would i make a pokemon base stat go higherthan 255? i know this requirs asm and if i over looked it and its in this tut plz tell me so your time isn't wasted any more

colcolstyles
January 4th, 2011, 02:30 PM
quick question, how would i make a pokemon base stat go higherthan 255? i know this requirs asm and if i over looked it and its in this tut plz tell me so your time isn't wasted any more

You will have to expand the pokémon data structure so that the six base stats will all be halfowrds (16-bit) instead of bytes (8-bit). You will also have to change the references to the data table because each entry (i.e., each pokémon's data) will now be longer. Then you'll have to hunt down every single routine that loads a pokémon's base stats and change them so that each one loads halfwords instead of bytes. You possibly will also have to make some changes to these routines as they will be interpreting the data as bytes.

In other words, just give up.

NintendoBoyDX
January 6th, 2011, 01:07 PM
Quick question. When you load the status byte and want to separate the 3 sleep bits, why not just and it by 7? I'm just starting out with assembly but I was wondering why you shifted the bits to clear instead of just using and.

Xenesis
January 6th, 2011, 06:21 PM
Using shifts to clear bits has it's advantages. Mainly because to and something you need to load a value into a register and then and between two registers. Using bitshifts to cut off bits you don't care about is often simpler because it requires only one register.

Basically, as a consequence of the processor design there's no function for AND rX, Value, just AND rX, rY

Here's a summary of all the ALU operations from gbatek:

THUMB.4: ALU operations

Opcode Format

Bit Expl.
15-10 Must be 010000b for this type of instructions
9-6 Opcode (0-Fh)
0: AND Rd,Rs ;AND logical Rd = Rd AND Rs
1: EOR Rd,Rs ;XOR logical Rd = Rd XOR Rs
2: LSL Rd,Rs ;log. shift left Rd = Rd << (Rs AND 0FFh)
3: LSR Rd,Rs ;log. shift right Rd = Rd >> (Rs AND 0FFh)
4: ASR Rd,Rs ;arit shift right Rd = Rd SAR (Rs AND 0FFh)
5: ADC Rd,Rs ;add with carry Rd = Rd + Rs + Cy
6: SBC Rd,Rs ;sub with carry Rd = Rd - Rs - NOT Cy
7: ROR Rd,Rs ;rotate right Rd = Rd ROR (Rs AND 0FFh)
8: TST Rd,Rs ;test Void = Rd AND Rs
9: NEG Rd,Rs ;negate Rd = 0 - Rs
A: CMP Rd,Rs ;compare Void = Rd - Rs
B: CMN Rd,Rs ;neg.compare Void = Rd + Rs
C: ORR Rd,Rs ;OR logical Rd = Rd OR Rs
D: MUL Rd,Rs ;multiply Rd = Rd * Rs
E: BIC Rd,Rs ;bit clear Rd = Rd AND NOT Rs
F: MVN Rd,Rs ;not Rd = NOT Rs
5-3 Rs - Source Register (R0..R7)
2-0 Rd - Destination Register (R0..R7)


As you can see, they only work between two registers (with the exception of the NOT/NEG operations).

NintendoBoyDX
January 6th, 2011, 06:36 PM
Using shifts to clear bits has it's advantages. Mainly because to and something you need to load a value into a register and then and between two registers. Using bitshifts to cut off bits you don't care about is often simpler because it requires only one register.
If I'm not mistaken though and directly edits the contents of one register, so it only requires one register as well.

colcolstyles
January 6th, 2011, 06:43 PM
I'm pretty sure it takes two. Let's say you have some value in r0. In order to clear the top 29 bits, you would have to load 7 into an arbitrary register and then AND the two. I can't think of any way to do it with only one register other than to use logical shifts. Plus, I think that the "mov" instruction takes up more cycles than logical shifts so it'll save you a nanosecond or two. :D

Xenesis
January 6th, 2011, 06:44 PM
If I'm not mistaken though and directly edits the contents of one register, so it only requires one register as well.

Yes, that's correct.

However, you can't AND an immediate value in code, you have to AND two registers.

Eg, you can't go:

AND r0, #0x3

because the hardware doesn't support it.

You have to go something like:

MOV r1, #0x3
AND r0, r1

Which requires two free registers. If you want to clear bits, you can just do something like:

lsl r0, r0, #0x19
lsr r0, r0, #0x19

Which only requires one free register.

Plus, I think that the "mov" instruction takes up more cycles than logical shifts so it'll save you a nanosecond or two. :D

The difference between the two is generally rather minor. You're unlikely to add much bloat to the game's code as is unless you start abusing swi operations relentlessly.

colcolstyles
January 6th, 2011, 06:59 PM
The difference between the two is generally rather minor. You're unlikely to add much bloat to the game's code as is unless you start abusing swi operations relentlessly.

True, although if the code is in a loop and you're already pressed for time (which you shouldn't be if you're hacking a commercial ROM), it could possibly make a difference. Actually, if this is to be used in a loop, you're probably better off "mov"-ing the 7 into a register outside the loop so that you only need one instruction (an "and") to clear bits while inside the loop.

NintendoBoyDX
January 6th, 2011, 07:37 PM
Thanks Xenesis, colcolstyles. There was just one more thing that wasn't clear to me:
.word 0x020270B6 + (0x800D * 2)
If the 0x8000-0x8013 variables are the only static one, how would there be an address of the "first" variable(I assume 0x0000), wouldn't it be DMA along with the rest?

BTW, looking at an example code from a tutorial JPAN posted a while ago, he subtracts 0x8000 from his variable values, multiplies them by 4, then finally adds that to the 0x8000 variable's address. I don't understand why it would be necessary to do that(or how that works quite frankly), even though with the code in this tutorial you can simply store the value to loaded variable.
Here was the code:
.align 2
.thumb
Var_adder: push {r0-r2, lr}
Ldr r0, first_var_addr @this will load the address of that lable
Ldrh r0, [r0, #0x0] @and this will load its content.
Ldr r1, second_var_addr
Ldrh r1, [r1, #0x0] @both variable numbers are loaded
Lsl r2, r2, #0x10 @cleans the bottom half of register r2
Add r2, r2,#0x8 @places 0x8 in r2
Lsl r2, r2, #0xc @and this turns 0x8 in 0x8000, and cleans the rest @of r2
Sub r1, r1, r2 @leaves only the last value in
Sub r0, r0, r2 @each variable.
Lsl r1, r1, #0x2 @after multiplied by 4, It becomes the
@offset of that address
Ldr r2, var_8000_addr
Lsl r0, r0, #0x2 @same here.
Add r0, r2, r0 @by adding the variable address to the offest
Add r1, r2, r1 @you get the correct variable address
Ldrh r2, [r0, #0x0] @now we load the content of the variables we
Ldrh r1, [r1, #0x0] @want to add
Add r2, r1, r2 @and add them
Strh r2, [r0, #0x0] @the result, that is in r2, is placed in the first @variable, the one in 0x8013
Pop {r0-r2, pc} @and we’re done

first_var_addr: .word 0x020370dc
second_var_addr:.word 0x020370de
var_8000_addr:.word 0x020370b8

阴魂君
February 3rd, 2013, 08:11 PM
Excuse me,I don't know why,but I can't download the asm pack in China... Could you please send it to my email? My email address is [email protected]
thanks a lot >_<

eugarps
October 23rd, 2014, 10:33 AM
The Dropbox link seems to be broken. Could I get a mirror/email ([email protected])with the files? Thank you

divinemamgai
November 3rd, 2014, 05:04 AM
The Link is dead, can you please provide me a mirror? Email - [email protected]

Volt-Ikazuchi
November 24th, 2014, 07:20 AM
Just curious here, I would need to use ASM to block players from challenging certain trainers (Gym Leaders, Rivals) with pokémons above a certain level, right?
What if I need to block items during a certain battle?

I'm just starting out, so I wanted to make my first hack more simple to understand mapping and scripting better, but if I need ASM to get some level and item caps then I'll have to learn it as well.

Thanks for the tutorial, looks very interesting, I'll definitely read it later.

FBI agent
November 24th, 2014, 08:27 AM
Just curious here, I would need to use ASM to block players from challenging certain trainers (Gym Leaders, Rivals) with pokémons above a certain level, right?
What if I need to block items during a certain battle?

I'm just starting out, so I wanted to make my first hack more simple to understand mapping and scripting better, but if I need ASM to get some level and item caps then I'll have to learn it as well.

Thanks for the tutorial, looks very interesting, I'll definitely read it later.

For blocking players from challenging certain trainers depending on party pokemon level you need some asm, but it's just function calls, nothing down and dirty.

For the item one, you'd need a battle script (look up Jambo's battle script tutorial/tool). Though admittedly, battle scripts are also very technical P:

Volt-Ikazuchi
November 26th, 2014, 07:48 AM
For blocking players from challenging certain trainers depending on party pokemon level you need some asm, but it's just function calls, nothing down and dirty.

For the item one, you'd need a battle script (look up Jambo's battle script tutorial/tool). Though admittedly, battle scripts are also very technical P:

Really? That's great news!

Mind to elaborate what asm routines I would need to do the level caps?
I really don't want to go in blind and break the game.
And are you saying that locking the items mid-battle require just some scripting? Can it be done in XSE or would I need Jambo's tool?

Thanks for the answers. Really helped.

FBI agent
November 26th, 2014, 08:11 AM
Really? That's great news!

Mind to elaborate what asm routines I would need to do the level caps?
I really don't want to go in blind and break the game.
And are you saying that locking the items mid-battle require just some scripting? Can it be done in XSE or would I need Jambo's tool?

Thanks for the answers. Really helped.

Sure, for the prevention of player challenging trainers, it's 90% handled by the trainer script.

I would do this:

#dyn 0x740000
#org @start
lock
faceplayer
setvar 0x4011 0x[max level of trainer]
callasm 0x[asm that returns max pokemon level in party]
compare 0x4001 LASTRESULT
if > jump @ignore
trainerbattle 0x0 0xID 0x0 @intro @defeat
msgbox @afterwards
callstd MSG_NORMAL
release
end

#org @ignore
msgbox @noThanks
callstd MSG_NORMAL
release
end

#org @noThanks
= Sorry, you wouldn't be a\nchallenge to me!

#org @intro
= Battle started, say something

#org @defeat
= defeat text

#org @afterwards
= Nice battle.


For the item blocking, I have no idea. I think Jambo's tutorial on Battle scripts covers it iirc.

DizzyEgg
December 30th, 2014, 10:56 AM
Some images in the tutorial are missing. Could someone upload them?

ZapdosMan
January 2nd, 2015, 01:19 AM
Wow I think this is a really good tutorial
though i find it hard to understand but finally someone posted a tutorial on this

Thanks

ZapdosMan

Sounak
February 16th, 2015, 12:02 AM
The download link to your ASM pack is not working.
Can you re-upload it please.

DizzyEgg
February 20th, 2015, 11:42 AM
I have a problem with your first routine. Here's what I got http://i.imgur.com/obuckLm.png
My code: .align 2
.thumb
main:
push {r0-r1,lr}
ldr r0, pokemon_data
ldrh r0, [r0]
ldr r1, var
strh r0, [r1]
pop {r0-r1, pc}

.align 2
pokemon_data: .word 0x02024284 + 0x54
var: .word 0x20370D0
I also tried those ( 03 B5 02 48 80 88 02 49 08 80 03 BD 84 42 02 02 D0 70 03 02 ) assembled numbers and still got the same result. Why is this happening?

GoGoJJTech
February 20th, 2015, 01:15 PM
I have a problem with your first routine. Here's what I got http://i.imgur.com/obuckLm.png
My code: .align 2
.thumb
main:
push {r0-r1,lr}
ldr r0, pokemon_data
ldrh r0, [r0]
ldr r1, var
strh r0, [r1]
pop {r0-r1, pc}

.align 2
pokemon_data: .word 0x02024284 + 0x54
var: .word 0x20370D0
I also tried those ( 03 B5 02 48 80 88 02 49 08 80 03 BD 84 42 02 02 D0 70 03 02 ) assembled numbers and still got the same result. Why is this happening?

That routine seems to be a failure. You're trying to load the level but you're loading a halfword (two bytes).
Change "ldrh r0, [r0]" to "ldrb r0, [r0]"

FBI agent
February 20th, 2015, 01:32 PM
I have a problem with your first routine. Here's what I got http://i.imgur.com/obuckLm.png
My code: .align 2
.thumb
main:
push {r0-r1,lr}
ldr r0, pokemon_data
ldrh r0, [r0]
ldr r1, var
strh r0, [r1]
pop {r0-r1, pc}

.align 2
pokemon_data: .word 0x02024284 + 0x54
var: .word 0x20370D0
I also tried those ( 03 B5 02 48 80 88 02 49 08 80 03 BD 84 42 02 02 D0 70 03 02 ) assembled numbers and still got the same result. Why is this happening?

Hi. If I'm understanding this correctly, you're trying to check the Pokemon's level (hence 0x02024284 + 0x54) ? Well a Pokemon's level is 0-100, which can be represented in hex as 1 byte (0x64 being 100)


ldr r0, pokemon_data
ldrh r0, [r0]

You're loading a half word (2 bytes) which is going to load something extra as well. Try ldrb instead of ldrh.

DizzyEgg
February 21st, 2015, 12:14 AM
Hi. If I'm understanding this correctly, you're trying to check the Pokemon's level (hence 0x02024284 + 0x54) ? Well a Pokemon's level is 0-100, which can be represented in hex as 1 byte (0x64 being 100)


ldr r0, pokemon_data
ldrh r0, [r0]
You're loading a half word (2 bytes) which is going to load something extra as well. Try ldrb instead of ldrh.

That routine seems to be a failure. You're trying to load the level but you're loading a halfword (two bytes).
Change "ldrh r0, [r0]" to "ldrb r0, [r0]"

It worked perfectly. Thank you!