• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Research: Feebas tiles in R/S/E

13
Posts
9
Years
(Sorry for the lack of links and pictures - The forum actually prevents me from pasting links until I've made fifteen posts)

So quite recently, I've been interested by the workings of Feebas's spawning mechanics in R/S/E. I may not have a lot of experience in Pokémon Hacking, but I have some in reversing, and I figured this'd be a way to get me started.

A lot of Googling has taught me the following:
- Speaking to the NPC in Dewford Town will update the tiles if the new "trendy" sentence passed is accepted (Which is itself something luck-based)
- Saving the game and rebooting keeps the "Feebas tiles".
- Using the same trendy sentence of two games does not yield the same tiles.
- On Feebas tiles, you can either get Feebas or Carvanha.
- There are only 6 Feebas tiles.

I noticed that some save data blocks are not yet documented on Bulbapedia, so I figured that the data would be stored in there. Since tiles persist during saves, the game either saves Feebas tiles raw, or uses some vodoo to achieve the same in a compact way.

Starting from here, everything relates to Pokemon Emerald (U).

I've started by taking a look at Route 119. Looking at the Wild Pokémon Encounters, i saw Magikarp, Tentacool, and ... a ton of Carvanhas.

img11.hostingpics.net/pics/783244Feebas1.png

My first intuiton was then "Oh, the game probably rolls a number and changes one of these encounters to a Feebas if the roll is successful."
I imagined that the map would do something Feebas-related on its scripts - so I went ahead and took a look inside:

In the spoiler below is the result of the map scripts - Nothing useful in there from what I can see, so skip ahead for the related-stuff.
Spoiler:


At this point i just went to take a look at the Trendy Sentence NPC's script.

Code:
#org 0x81E9922
'-----------------------------------
lock
faceplayer
call 0x8271E8B
msgbox 0x81EA136 ' I like what's hip, h...
callstd MSG_YESNO ' Yes/No message
compare LASTRESULT YES
if == jump 0x81E9948 ' Equal To
compare LASTRESULT 0x0
if == jump 0x81E9952 ' Equal To
end

#org 0x8271E8B
'-----------------------------------
CMD_2D
setvar 0x8004 0x0
special 0x81
return

#org 0x81E9948
'-----------------------------------
msgbox 0x81EA491 ' Yeah, absolutely rig...
callstd MSG_NOCLOSE ' Non-closing message
release
     ' Release commands close any open messages
end

#org 0x81E9952
'-----------------------------------
msgbox 0x81EA242 ' Hunh?\nIt's not the ...
callstd MSG_NOCLOSE ' Non-closing message
setvar 0x8004 0x9
call 0x8271E7C
lock
faceplayer
compare LASTRESULT 0x1
if == jump 0x81E997D ' Equal To
compare LASTRESULT 0x0
if == jump 0x81E9994 ' Equal To
end

#org 0x8271E7C
'-----------------------------------
fadescreen FADEOUT_BLACK
special 0x62
fadescreen FADEIN_BLACK
return

#org 0x81E997D
'-----------------------------------
CMD_C3 0x2
compare 0x8004 0x0
if == jump 0x81E999E ' Equal To
msgbox 0x81EA2AA ' Hunh?\n"\v\h03["]?\p...
callstd MSG_NOCLOSE ' Non-closing message
release
     ' Release commands close any open messages
end

#org 0x81E999E
'-----------------------------------
msgbox 0x81EA3FE ' Hmm[.]\n"\v\h03,["] ...
callstd MSG_NOCLOSE ' Non-closing message
release
     ' Release commands close any open messages
end

#org 0x81E9994
'-----------------------------------
msgbox 0x81EA443 ' Well, if you hear of...
callstd MSG_NOCLOSE ' Non-closing message
release
     ' Release commands close any open messages
end


#org 0x81EA136
= I like what's hip, happening, and trendy.\nI'm always checking it out.\pListen, have you heard about this new\n"\v\h02["]?\pThat's right!\nOf course you know!\pI mean, sheesh,\n"\v\h02["][.]\lIt's the hottest thing in cool!\pWherever you're from,\n"\v\h02["]\lis the biggest happening thing, right?

#org 0x81EA491
= Yeah, absolutely right!\p"\v\h02["] is the\ndefinition of "in["] right now.

#org 0x81EA242
= Hunh?\nIt's not the hip and happening thing?\pWell, hey, you have to tell me,\nwhat's new and what's "in["]?

#org 0x81EA2AA
= Hunh?\n"\v\h03["]?\p[.] [.]\p[.]Uh[.] Yeah! That's right!\nYeah, I knew that! Knew it all along!\pOf course I know about that!\n"\v\h03,["] right?\pYeah, that's it, it's there!\nIsn't "\v\h03["]\lthe coolest, or what?\pIt's the hippest thing in hip.\nYou think I'd not know about it?\p"\v\h02["][.]\nIt's, like, so five minutes ago.\pNow, "\v\h03["] is\nwhat's vital and in tune with the times!

#org 0x81EA3FE
= Hmm[.]\n"\v\h03,["] huh?\pBut personally, I think\n"\v\h02["]\lis what's real in cool.

#org 0x81EA443
= Well, if you hear of any happening new\ntrends, come share them with me, okay?

0x81E12AA is the success string, which is called by this chunk of code

Code:
#org 0x81E997D
'-----------------------------------
CMD_C3 0x2
compare 0x8004 0x0
if == jump 0x81E999E ' Equal To
msgbox 0x81EA2AA ' Hunh?\n"\v\h03["]?\p...

Now this beats me. What does CMD_C3 0x2 do ? I get that if data at 0x8004 is equal to 0, the NPC will refuse the new Trendy String. I assume this is calling some magic that rolls to see if the input string will be accepted, and then seeds the "Feebas tiles".

So from there, where should I look ? I'm soon going to pop open the ROM in Ida Pro and see what i can find, but I only have a vague idea where to look (save file loaders, most probably)

I'd definitely love some help on this, for the sake of documenting, reversing, and fun! So thanks for all your inputs :D
 
13
Posts
9
Years
It appears that people over at Smogon have already taken a look at this; see end of post for hidden links (Silly 15 messages limit).

I won't repaste everything, but here is the most important part

Code:
ROM:080B4A98 sub_80B4A98                             ; CODE XREF: ROM:loc_80B4A1Ap
ROM:080B4A98                 LDR     R2, =0x2038C04
ROM:080B4A9A                 LDR     R1, [R2]
ROM:080B4A9C                 LDR     R0, =0x41C64E6D
ROM:080B4A9E                 MULS    R0, R1
ROM:080B4AA0                 LDR     R1, =0x3039
ROM:080B4AA2                 ADDS    R0, R0, R1
ROM:080B4AA4                 STR     R0, [R2]
ROM:080B4AA6                 LSRS    R0, R0, #0x10   ; (Offset 0x2038C04) = (0x41C64E6D * seed + 0x3039)
ROM:080B4AA8                 BX      LR
ROM:080B4AA8 ; End of function sub_80B4A98


               LSLS    R0, R0, #0x10   ; Beginning of feebas stuff
ROM:080B49F4                 LSRS    R0, R0, #0x10
ROM:080B49F6                 CMP     R0, #0x31
ROM:080B49F8                 BLS     loc_80B4A08
ROM:080B49FA                 B       loc_80B4A7A     ; If calculated slot is not feebas, skip determination routine
ROM:080B49FA ; ---------------------------------------------------------------------------
ROM:080B49FC dword_80B49FC   DCD 0x3005D8C           ; DATA XREF: ROM:080B4990r
ROM:080B4A00 off_80B4A00     DCD unk_8553A7C         ; DATA XREF: ROM:080B49BCr
ROM:080B4A04 ; ---------------------------------------------------------------------------
ROM:080B4A04
ROM:080B4A04 loc_80B4A04                             ; CODE XREF: ROM:080B4A6Ej
ROM:080B4A04                 MOVS    R0, #1
ROM:080B4A06                 B       loc_80B4A7C
ROM:080B4A08 ; ---------------------------------------------------------------------------
ROM:080B4A08
ROM:080B4A08 loc_80B4A08                             ; CODE XREF: ROM:080B49F8j
ROM:080B4A08                 LDR     R0, =0x3005D8C
ROM:080B4A0A                 LDR     R0, [R0]
ROM:080B4A0C                 LDR     R3, =0x2E6A
ROM:080B4A0E                 ADDS    R0, R0, R3
ROM:080B4A10                 LDRH    R0, [R0]        ; Feebas seed is in R0
ROM:080B4A12                 BL      sub_80B4AB8
ROM:080B4A16                 MOVS    R5, #0          ; R5 (loop counter) = 0
ROM:080B4A18                 LDR     R6, =0x1BF      ; R6 = 0x01BF
ROM:080B4A1A
ROM:080B4A1A loc_80B4A1A                             ; CODE XREF: ROM:080B4A4Cj
ROM:080B4A1A                 BL      sub_80B4A98     ; Stores recalculated seed at 0x2038C04
ROM:080B4A1E                 LSLS    R1, R5, #1      ; R1 = 0
ROM:080B4A20                 MOV     R2, SP          ; R2 = SP
ROM:080B4A22                 ADDS    R4, R2, R1      ; R4 = R2 + (R1 = 0)
ROM:080B4A24                 LSLS    R0, R0, #0x10
ROM:080B4A26                 LSRS    R0, R0, #0x10
ROM:080B4A28                 MOVS    R1, R6          ; R1 = R6 = 0x01BF
ROM:080B4A2A                 BL      sub_82E7BE0     ; R0 = R0 % R1
ROM:080B4A2E                 STRH    R0, [R4]        ; Stores R0 (Current tile) on stack
ROM:080B4A30                 LSLS    R0, R0, #0x10
ROM:080B4A32                 CMP     R0, #0          ; If R0 == 0
ROM:080B4A34                 BNE     loc_80B4A38     ; Load calculated feebas tile into R0
ROM:080B4A36                 STRH    R6, [R4]        ; Store 0x1BF instead
ROM:080B4A38
ROM:080B4A38 loc_80B4A38                             ; CODE XREF: ROM:080B4A34j
ROM:080B4A38                 LDRH    R0, [R4]        ; Load calculated feebas tile into R0
ROM:080B4A3A                 SUBS    R0, #1          ; R0 -= 1
ROM:080B4A3C                 LSLS    R0, R0, #0x10   ; These LSLS and LSLR clear a bit
ROM:080B4A3E                 LSRS    R0, R0, #0x10
ROM:080B4A40                 CMP     R0, #2          ; Tile type. If it's <= 3, don't increment the loop counter (R5), so generate new tiles to check against
ROM:080B4A42                 BLS     loc_80B4A4A
ROM:080B4A44                 ADDS    R0, R5, #1      ; R0 = R5 + 1
ROM:080B4A46                 LSLS    R0, R0, #0x18
ROM:080B4A48                 LSRS    R5, R0, #0x18   ; R5 = R0 (This basically does ++R5)
ROM:080B4A4A
ROM:080B4A4A loc_80B4A4A                             ; CODE XREF: ROM:080B4A42j
ROM:080B4A4A                 CMP     R5, #6          ; If R5 < 6
ROM:080B4A4C                 BNE     loc_80B4A1A     ; Calculate another feebas tile to check against
ROM:080B4A4E                 MOV     R3, R9          ; R3 = R9
ROM:080B4A50                 MOVS    R1, #0          ; R1 = 0
ROM:080B4A52                 LDRSH   R0, [R3,R1]     ; R0 = rod->map.x (Fishing X coordinate)
ROM:080B4A54                 MOV     R2, R8
ROM:080B4A56                 MOVS    R3, #0
ROM:080B4A58                 LDRSH   R1, [R2,R3]     ; R1 = rod->map.y (Fishing Y coordinate)
ROM:080B4A5A                 MOVS    R2, R7          ; R2 = R7
ROM:080B4A5C                 BL      sub_80B48C4     ; From current fishing coordinates return tile number in R0
ROM:080B4A60                 LSLS    R0, R0, #0x10   ; R0 = R0 << 0x10
ROM:080B4A62                 LSRS    R1, R0, #0x10   ; R1 = R0 >> 0x10
ROM:080B4A64                 MOVS    R5, #0          ; R5 = 0
ROM:080B4A66
ROM:080B4A66 loc_80B4A66                             ; CODE XREF: ROM:080B4A78j
ROM:080B4A66                 LSLS    R0, R5, #1      ; R0 = R5 << 0x1
ROM:080B4A68                 ADD     R0, SP          ; R0 += SP
ROM:080B4A6A                 LDRH    R0, [R0]        ; Load *R0 into R0
ROM:080B4A6C                 CMP     R1, R0          ; Compare R0 and R1
ROM:080B4A6C                                         ; If result flag is set to 1, this is a feebas tile. BREAKPOINT HERE
ROM:080B4A6E                 BEQ     loc_80B4A04     ; feebasTile = true
ROM:080B4A70                 ADDS    R0, R5, #1      ; ...
ROM:080B4A72                 LSLS    R0, R0, #0x18   ; ...
ROM:080B4A74                 LSRS    R5, R0, #0x18   ; ... Increments R5
ROM:080B4A76                 CMP     R5, #5          ; if  R5 < 6 ...
ROM:080B4A78                 BLS     loc_80B4A66     ; ... loop again
ROM:080B4A7A
ROM:080B4A7A loc_80B4A7A                             ; CODE XREF: ROM:080B499Cj
ROM:080B4A7A                                         ; ROM:080B49FAj
ROM:080B4A7A                 MOVS    R0, #0          ; R0 is not a feebas tile.
ROM:080B4A7C
ROM:080B4A7C loc_80B4A7C                             ; CODE XREF: ROM:080B4A06j
ROM:080B4A7C                 ADD     SP, SP, #0x10
ROM:080B4A7E                 POP     {R3,R4}
ROM:080B4A80                 MOV     R8, R3
ROM:080B4A82                 MOV     R9, R4
ROM:080B4A84                 POP     {R4-R7}
ROM:080B4A86                 POP     {R1}
ROM:080B4A88                 BX      R1

From there, we can do the following:
if result of 080B4A6C != 0 // Feebas tile
--> execute 080B4A4E to 080B4A58 to get tile X and Y coordinates
--> highlight tiles on the map.

However, one more place where I am clueless: Are there any emulators out there that allow to write small programs in any language, that then interpretes given code, and spits out the result in a console ? I could go slowpoke and breakpoint all three instructions (if feebas tile, tile X, tile Y) and store tile X & Y values IFF feebas tile is true, but that'd be slow since I'm going to loop over all the tiles in the river.

Alternatively, one can easily extract the seed, redo what this thing does in C, and compute the tiles on the fly.

This was done on a Pokemon Emerald (U) ROM.

Links used:
(Smogon) forums/ threads/ past-gen-rng-research.61090/ page-34 (Huge kudos to you, good sir!)
 
13
Posts
9
Years
More looking at this in VBA's debugger told me that the value at the actual pointer changes everytime you fish - looks like it's actually moved around: I saw it a few bytes further away, then it dissapeared from the memory viewer's screen for some time, then reappeared. So reading it from memory is not actually relevant at all time. I'll toy more with this.

I don't think I'll write a VBA addin for that though, because A) code in C is already there in the link on my previous post, and you can just put it on ideone.com, enter initial seed, and compute your tiles, and B) reason A is long enough.
 
29
Posts
10
Years
  • Age 25
  • Seen Oct 23, 2017
Man, Feebas was so darn hard to catch..... I wonder if they will do the same in ORAS.... :/
 
13
Posts
9
Years
Have you taken a look using the Debugger Pokémon Ruby? There's a testing menu option that shows you the Feebas fishing spots. And it works, too. I've been able to actually fish for them and catch them in their locations.

I had no clue this was leaked, I'll dig it! Thanks for sharing the info
 
Back
Top