Changing global wild encounter levels (Emerald)
** Again, something I did for my own uses. Instead of changing the wild encounter tables for each route, you can make sweeping changes to all wild encounters by changing the code that uses those tables.
This is what the flow for generating wild encounters looks like (call order):
ROM:080B5288 walking_func
ROM:080B4F4C choose_wild_pokemon_encounter
ROM:080B4C74 choose_encounter_level
The first function performs some check for every step (or turn) the player takes. If the player's tile is encounter-eligible it enters the second function, which eventually calls the third function, "choose_encounter_level" which does just that. Let's look at some pseudo-code:
Code:
int __fastcall choose_encounter_level(int encounter_table)
{
int encounter_table_loc; // [email protected]
unsigned int v2; // [email protected]
int level_min; // [email protected]
unsigned int level_max; // [email protected]
int rand; // [email protected]
int v6; // [email protected]
int v7; // [email protected]
encounter_table_loc = encounter_table;
v2 = *(_BYTE *)(encounter_table + 1);
if ( v2 < *(_BYTE *)encounter_table_loc )
{
level_min = *(_BYTE *)(encounter_table_loc + 1);
level_max = *(_BYTE *)encounter_table_loc;
}
else
{
level_min = *(_BYTE *)encounter_table_loc;
level_max = v2;
}
rand = (unsigned __int16)rng() % (signed int)((level_max - level_min + 1) & 0xFF) & 0xFF;
if ( !pokemon_getattr(0x20244EC, 6, v6) )
{
v7 = (unsigned __int8)sub_806B6D8(0x20244EC);
if ( v7 == 55 || v7 == 72 || v7 == 46 )
{
if ( !(rng() & 1) )
return level_max;
if ( rand )
rand = (rand - 1) & 0xFF;
}
}
return (level_min + rand) & 0xFF;
}
Only some of the stuff here I found important, mostly the computation for "rand". It's worth clarifying that "level_min" etc. are encounter-specific, and come straight out of the encounter tables. Here are the relevant opcodes:
Computing "rand"
Code:
ROM:080B4C8A F4 1B SUBS R4, R6, R7
ROM:080B4C8C 01 34 ADDS R4, #1
ROM:080B4C8E 24 06 LSLS R4, R4, #0x18
ROM:080B4C90 24 0E LSRS R4, R4, #0x18
ROM:080B4C92 BA F7 9B FC BL rng
ROM:080B4C96 00 04 LSLS R0, R0, #0x10
ROM:080B4C98 00 0C LSRS R0, R0, #0x10
ROM:080B4C9A 21 1C MOVS R1, R4
ROM:080B4C9C 32 F2 D8 FC BL __modsi3
ROM:080B4CA0 00 06 LSLS R0, R0, #0x18
ROM:080B4CA2 04 0E LSRS R4, R0, #0x18
On entering:
- R6 is level_min
- R7 is level_max
On leaving:
Returning "rand" as the encounter level
Code:
ROM:080B4CEA 38 19 ADDS R0, R7, R4
ROM:080B4CEC 00 06 LSLS R0, R0, #0x18
ROM:080B4CEE 00 0E LSRS R0, R0, #0x18
- R4 and R7 keep their values from the "rand" computation - "rand" and "level_min" respectively.
Use cases
So, what now? Well, say you wanted to make encounters a bit scarier - it's as easy as adding to R4 or R7. In my own experiments I replaced the useless left-shift/right-shift opcodes near the "rand" computation with something more useful:
Code:
ROM:080B4C8A SUBS R4, R6, R7
ROM:080B4C8C ADDS R4, #1
ROM:080B4C8E LDR R5, =0x3005D8C
ROM:080B4C90 LDR R5, [R5,#4]
ROM:080B4C92 BL rng
ROM:080B4C96 LDRB R5, [R5,#0x14]
ROM:080B4C98 NOP
ROM:080B4C9A MOVS R1, R4
ROM:080B4C9C BL __modsi3
ROM:080B4CA0 LSRS R5, R5, #3
ROM:080B4CA2 ADDS R4, R0, R5
Since R5 was unused, I borrowed it to add to "rand" the message frame value! You know, the value in the options that decides what pretty frame your menus have (I prefer the pink one with the bows!). Based on this research:
showthread.php?p=8615361#post8615361
The value's behind pointer 0x3005D90, offset 0x14. The reason I counted from 0x3005D8c is convenience - it's used a bit later at 080B4D50:
Code:
ROM:080B4D50 dword_80B4D50 DCD 0x3005D8C