Re: Random events in Telefang

Discuss anything related to hacking ROMs of the Telefang games here.
Post Reply
Blaziken257
Posts: 983
Joined: Fri Dec 22, 2006 11:52 am

Re: Random events in Telefang

Post by Blaziken257 »

I've been meaning to post this for a long time, but now I have time to do it... This post is a long explanation of how the game handles random events: how random numbers are generated, and the probabilities of various things. This will cover various aspects, such as which wild Denjuu appear, running from random battles, and more.

The first important thing to know is how random numbers are generated in the first place. The same function for random numbers is used for every random event in the game: wild Denjuu (including their species and level), whether you can run from a battle or not (except in predetermined fights, where you can never escapee), what move an opponent Denjuu will use, whether a Denjuu will be affected by its personality (for example, if it doesn't want to attack in a given turn), whether an attack will miss or not, critical hits, the amount of damage dealt by an attack, added effects like paralysis (if applicable), or whether a Denjuu will give you its phone number or not. There may be other examples of this too.

This random number generation function is at 000D4E-000D7C in the ROM, and since it will be used for everything, I will post the assembly code, taken from BGB's debugger (this is a very helpful emulator here). To use BGB's debugger, open a ROM, then right-click the window and go to other->debugger. Any comments on the right are added by me for a bit of clarity.
Spoiler!

Code: Select all

ROM0:0D4E FA 70 C4         ld   a,(C470)
ROM0:0D51 FE 02            cp   a,02     ; I've ALWAYS seen a (RAM address C470) set to 00, so ignore this
ROM0:0D53 CA 7D 0D         jp   z,0D7D
ROM0:0D56 E5               push hl
ROM0:0D57 C5               push bc
ROM0:0D58 FA 1F C4         ld   a,(C41F) ; Reads RAM address C41F (Seed #1)
ROM0:0D5B 67               ld   h,a
ROM0:0D5C FA 20 C4         ld   a,(C420) ; Reads RAM address C420 (Seed #2)
ROM0:0D5F 6F               ld   l,a
ROM0:0D60 FA C0 C3         ld   a,(C3C0) ; Reads RAM address C3C0 (increases every frame)
ROM0:0D63 47               ld   b,a
ROM0:0D64 CB 37            swap a        ; this swaps nibbles in a (frame counter); e.g. 9D becomes D9
ROM0:0D66 3C               inc  a        ; adds 1 to a (frame counter)
ROM0:0D67 CB 3F            slr a         ; Logical right bit shift to frame counter (essentially divides by 2 but leftmost bit will always be 0, useful for unsigned integers)
ROM0:0D69 C6 87            add  a,87     ; Adds 0x87 (135) to a (frame counter)
ROM0:0D6B 4F               ld   c,a      ; a gets loaded into c (c is the lower 8 bits of bc)
ROM0:0D6C 09               add  hl,bc    ; adds bc to hl
ROM0:0D6D 7D               ld   a,l      ; l = Modified seed #2
ROM0:0D6E EA 1F C4         ld   (C41F),a ; Output new seed #1
ROM0:0D71 7C               ld   a,h      ; h = Modified seed #1
ROM0:0D72 AD               xor  l        ; Xor l with a
ROM0:0D73 EA 20 C4         ld   (C420),a ; Output new seed #2
ROM0:0D76 85               add  l        ; Add l to a
ROM0:0D77 EA 00 C4         ld   (C400),a ; Output randomly generated number (sum of newly generated seeds) to RAM address C400
ROM0:0D7A C1               pop  bc
ROM0:0D7B E1               pop  hl
ROM0:0D7C C9               ret  
So basically, it takes values from addresses C3C0, C41F, and C420 from RAM. (Indeed, if you use GameShark codes to set these to constant values, you'll get the same results every time for everything.) C3C0 increments itself every frame, except for when the game is busy loading something. This makes random events dependent on timing. C41F and C420 are, basically, seeds that further influence the randomness, and they undergo a series of operations, which causes them to change after every random event. All of these variables get calculated to a final variable, at address C400 (which is a sum of the two newly generated seeds), which is used to then determine random events by comparing them with other values, depending on the event. This algorithm seems largely obfuscated, but I'm going to assume that C400 is uniform (i.e. there is an equal probability of it generating any number from 0-255), unless someone can prove me wrong.

So indeed, if you set a breakpoint at 0D4E (to do this, first open the debugger if it isn't already. Then double-click the gray space to the left of ROM0:0D4E), the emulator will stop here every time it does a random event. Then, when tracing the function, once it reaches ret, you can see what called the function, and therefore where a particular random event is. For now, let's look at a few -- I'm not going to cover every random event here yet, especially when I didn't look through them all yet.

First, let's look at the event that determines the species, level, and personality of a wild Denjuu. You may notice that on Wikifang 2.0, I noted a while ago that the median level was 50%, while there is a 25% probability each of it either subtracting or adding a level. In addition, I also noted that while there are four Denjuu per acre, the probabilities are not uniform -- there's one that has a 10% chance of appearing, one with a 20% chance, another with a 30% chance, and finally one with a 40% chance. Now let's explain this here. First we'll do the species:

The function for determining a species starts at 3C57. Now let's look at it!
Spoiler!

Code: Select all

ROM0:3C57 21 EE 56         ld   hl,56EE  ; Load from ROM address 1D56EE (the bank was determined elsewhere)
ROM0:3C5A 11 05 00         ld   de,0005  ; Each Denjuu group has 5 bytes (four for species and one for level -- this value is used to increment)
ROM0:3C5D FA 02 D4         ld   a,(D402) ; RAM address D402 is the group of wild Denjuu -- this byte was set elsewhere
ROM0:3C60 FE 00            cp   a,00     ; Loop: Takes value of Denjuu group, and increments pointer by 5 (in order to read the group of Denjuu/level from the proper place in ROM), then decrements value of Denjuu group by 1 -- this repeats until value of Denjuu group is finally 0
ROM0:3C62 28 04            jr   z,3C68   
ROM0:3C64 19               add  hl,de
ROM0:3C65 3D               dec  a
ROM0:3C66 20 FC            jr   nz,3C64
ROM0:3C68 E5               push hl
ROM0:3C69 CD 4E 0D         call 0D4E     ; RNG function as mentioned earlier
ROM0:3C6C FE 19            cp   a,19     ; *IMPORTANT* This determines the probabilites of every Denjuu. a = RNG number. If a < 0x19 (25), then pointer gets incremented by 3 (so it picks the fourth Denjuu from the list). This has a 25/256 or 9.8% chance of occurring.
ROM0:3C6E 38 0A            jr   c,3C7A
ROM0:3C70 FE 4C            cp   a,4C     ; If 25 <= a < 76, then pointer gets incremented by 2 (it picks the 3rd Denjuu). This has a 51/256 (19.9%) chance of occurring.
ROM0:3C72 38 07            jr   c,3C7B
ROM0:3C74 FE 99            cp   a,99     ; If 76 <= a < 153, then pointer gets incremented by 1 (it picks the 2nd Denjuu). This has a 77/256 (30.1%) chance of occurring.
ROM0:3C76 38 04            jr   c,3C7C
ROM0:3C78 18 03            jr   3C7D     ; Otherwise (if a => 153), then pointer doesn't change (it picks the 1st Denjuu). This has a 103/256 (40.2%) chance of occurring.
ROM0:3C7A 23               inc  hl
ROM0:3C7B 23               inc  hl
ROM0:3C7C 23               inc  hl
ROM0:3C7D 7E               ld   a,(hl)
ROM0:3C7E EA E0 D4         ld   (D4E0),a ; Output wild Denjuu to RAM address D4E0
ROM0:3C81 E1               pop  hl       ; hl (pointer to Denjuu data) reverts back to what it was before incrementing
So, as you can see from the comments (which I hope made sense), the probabilities are uneven. The 1st Denjuu from a list has a 40% chance of appearing, the 2nd has a 30% chance, and 3rd has a 20% chance, and the 4th has a meager 10% chance. So if you find that certain Denjuu are harder to find than others, then now you know why. Thankfully they made the Kochia at the beginning of Power appear only 10% of the time, so that's good.

And indeed, if you hack the bytes 3C6D, 3C71, and 3C75 with a hex editor (which are 19, 4C, and 99), you will find that different Denjuu are more likely to appear than others. Try it out! Make sure that each value is greater than the preceding one though.

Next, let's look at what determines the level, starting at 3C82 then going to 701B8:
Spoiler!

Code: Select all

ROM0:3C82 11 04 00         ld   de,0004  ; Value to increment pointer for median level
ROM0:3C85 19               add  hl,de    ; Increment pointer
ROM0:3C86 7E               ld   a,(hl)   ; Dereference pointer
ROM0:3C87 EA 9C D4         ld   (D49C),a ; RAM address D49C = Median level
ROM0:3C8A C9               ret           ; Eventually returns to 41B8

RO1C:41B8 FA E0 D4         ld   a,(D4E0) ; Read wild Denjuu species
RO1C:41BB 3D               dec  a        ; Subtract it by 1 (so that Tsunonasu starts at 0)
RO1C:41BC EA 42 D5         ld   (D542),a ; ???
RO1C:41BF FA 9C D4         ld   a,(D49C) ; D49C = Median level
RO1C:41C2 47               ld   b,a      ; b = Median level
RO1C:41C3 CD 4E 0D         call 0D4E     ; RNG function
RO1C:41C6 FE 40            cp   a,40     ; a = RNG number. If a < 64 (25% chance), then increment level by 1
RO1C:41C8 38 07            jr   c,41D1   
RO1C:41CA FE 80            cp   a,80     ; If 64 <= a < 128 (25% chance), then decrement level by 1
RO1C:41CC 38 07            jr   c,41D5
RO1C:41CE 78               ld   a,b
RO1C:41CF 18 06            jr   41D7
RO1C:41D1 78               ld   a,b
RO1C:41D2 3C               inc  a
RO1C:41D3 18 02            jr   41D7
RO1C:41D5 78               ld   a,b
RO1C:41D6 3D               dec  a
RO1C:41D7 EA 43 D5         ld   (D543),a ; Otherwise (if 128 <= a < 256) leave it alone... D543 = Wild Denjuu level
RO1C:41DA CD A1 42         call 42A1     ; Function for wild personality
Therefore, there is a 50% chance that the level is the median, and a 25% chance each that the level is offset by 1.
Next, let's look at the personality of the wild Denjuu, starting at offset 702A1:
Spoiler!

Code: Select all

RO1C:42A1 CD 4E 0D         call 0D4E     ; RNG function
RO1C:42A4 FE 14            cp   a,14     ; a = RNG number, if a < 20 then pick personality 0
RO1C:42A6 38 2C            jr   c,42D4
RO1C:42A8 FE 28            cp   a,28     ; if 20 <= a < 40 then pick personality 1
RO1C:42AA 38 2C            jr   c,42D8
RO1C:42AC FE 3C            cp   a,3C     ; if 40 <= a < 60 then pick personality 2
RO1C:42AE 38 2C            jr   c,42DC
RO1C:42B0 FE 50            cp   a,50     ; if 60 <= a < 80 then pick personality 3
RO1C:42B2 38 2C            jr   c,42E0
RO1C:42B4 FE 64            cp   a,64     ; if 80 <= a < 100 then pick personality 4
RO1C:42B6 38 2C            jr   c,42E4
RO1C:42B8 FE 78            cp   a,78     ; if 100 <= a < 120 then pick personality 5
RO1C:42BA 38 2C            jr   c,42E8
RO1C:42BC FE 8C            cp   a,8C     ; if 120 <= a < 140 then pick personality 6
RO1C:42BE 38 2C            jr   c,42EC
RO1C:42C0 FE A0            cp   a,A0     ; if 140 <= a < 160 then pick personality 7
RO1C:42C2 38 2C            jr   c,42F0
RO1C:42C4 FE B4            cp   a,B4     ; if 160 <= a < 180 then pick personality 8
RO1C:42C6 38 2C            jr   c,42F4
RO1C:42C8 FE C8            cp   a,C8     ; if 180 <= a < 200 then pick personality 9
RO1C:42CA 38 2C            jr   c,42F8
RO1C:42CC FE DC            cp   a,DC     ; if 200 <= a < 220 then pick personality 10
RO1C:42CE 38 2C            jr   c,42FC
RO1C:42D0 FE F0            cp   a,F0     ; if 220 <= a < 240 then pick personality 11; otherwise pick personality 0 (?)
RO1C:42D2 38 2C            jr   c,4300
RO1C:42D4 3E 00            ld   a,00
RO1C:42D6 18 2A            jr   4302
RO1C:42D8 3E 01            ld   a,01
RO1C:42DA 18 26            jr   4302
RO1C:42DC 3E 02            ld   a,02
RO1C:42DE 18 22            jr   4302
RO1C:42E0 3E 03            ld   a,03
RO1C:42E2 18 1E            jr   4302
RO1C:42E4 3E 04            ld   a,04
RO1C:42E6 18 1A            jr   4302
RO1C:42E8 3E 05            ld   a,05
RO1C:42EA 18 16            jr   4302
RO1C:42EC 3E 06            ld   a,06
RO1C:42EE 18 12            jr   4302
RO1C:42F0 3E 07            ld   a,07
RO1C:42F2 18 0E            jr   4302
RO1C:42F4 3E 08            ld   a,08
RO1C:42F6 18 0A            jr   4302
RO1C:42F8 3E 09            ld   a,09
RO1C:42FA 18 06            jr   4302
RO1C:42FC 3E 0A            ld   a,0A
RO1C:42FE 18 02            jr   4302
RO1C:4300 3E 0B            ld   a,0B
RO1C:4302 C9               ret  

RO1C:41DD EA 4E D5         ld   (D54E),a ; RAM address D54E = Personality
This one is weird. From a quick glance of looking at the code, it seems that personality 0 (whatever it is) seems to have a higher probability that the other ones. Is this an oversight, or did I read this code incorrectly? Either way it's weird. And no, I don't know what the personalities are offhand. Sorry. But the other ones are clearly uniform.

Finally, after all the wild Denjuu stuff, let's look at couple other things. First, the probability of escaping, starting from 70A99.
Spoiler!

Code: Select all

RO1C:4A99 FA 01 D5         ld   a,(D501) ; I'm not sure what this does
RO1C:4A9C 47               ld   b,a
RO1C:4A9D FA 43 D5         ld   a,(D543) ; Wild Denjuu personality?
RO1C:4AA0 B8               cp   b        ; Compare whatever is in address D501 with D543
RO1C:4AA1 30 13            jr   nc,4AB6  ; If (D543) >= (D501) then go to escape function??
RO1C:4AA3 FA 04 D5         ld   a,(D504) ; Not sure what this does
RO1C:4AA6 47               ld   b,a
RO1C:4AA7 FA 46 D5         ld   a,(D546)
RO1C:4AAA B8               cp   b
RO1C:4AAB 30 09            jr   nc,4AB6  ; If (D546) >= (D504) then go to escape function??
RO1C:4AAD CD 4E 0D         call 0D4E
RO1C:4AB0 FE 55            cp   a,55
RO1C:4AB2 38 10            jr   c,4AC4
RO1C:4AB4 18 08            jr   4ABE
RO1C:4AB6 CD 4E 0D         call 0D4E     ; call RNG function; this is also where escape function seems to start
RO1C:4AB9 FE C8            cp   a,C8     ; a = RNG number; if a < 200 (78.125% chance), then do not escape
RO1C:4ABB DA C4 4A         jp   c,4AC4
RO1C:4ABE 3E 01            ld   a,01     ; 01 = Able to escape
RO1C:4AC0 EA CD D5         ld   (D5CD),a ; D5CD = Flag to determine whether you were able to escape or not
RO1C:4AC3 C9               ret  
RO1C:4AC4 3E 00            ld   a,00     ; 00 = Couldn't escape
RO1C:4AC6 EA CD D5         ld   (D5CD),a
RO1C:4AC9 C9               ret  
I do not fully understand the first part, because I haven't looked into it enough. However, starting at 10AB6 (RO1C:4AB6), this function often seems to be called when trying to escape. From looking at it, it's a 200/256 (78.125%) chance of not being able to escape, and a 56/256 (21.875%) chance of being able to. I'm curious to what the code before it is though.

Last, but not least, let's look at the code for FD-related stuff. Here is the code for a Crypto with the personality that makes him choose the first move in the moveslot sometimes. I don't know if this is the same code for other personalites, like being late to battle or running early or whatnot. This starts at 14B38.
Spoiler!

Code: Select all

ROM5:4B35 FA 90 D5         ld   a,(D590) ; Not sure what any of this is
ROM5:4B38 FE 08            cp   a,08
ROM5:4B3A 28 04            jr   z,4B40
ROM5:4B3C FE 09            cp   a,09
ROM5:4B3E 20 4D            jr   nz,4B8D
ROM5:4B40 FA 8E D5         ld   a,(D58E) ; D58E = FD of Denjuu
ROM5:4B43 CB 27            sla a         ; Multiply FD by 2
ROM5:4B45 C6 37            add  a,37     ; Add 55 to FD
ROM5:4B47 47               ld   b,a      
ROM5:4B48 CD 4E 0D         call 0D4E     ; RNG function
ROM5:4B4B B8               cp   b        ; a = RNG number; b = FD; if a >= FD then exhibit personality flaw
ROM5:4B4C 38 3F            jr   c,4B8D
ROM5:4B4E FA 74 D4         ld   a,(D474)
ROM5:4B51 FE 01            cp   a,01
ROM5:4B53 28 0B            jr   z,4B60
ROM5:4B55 FE 02            cp   a,02
ROM5:4B57 28 0E            jr   z,4B67
ROM5:4B59 3E 01            ld   a,01
ROM5:4B5B EA CA D5         ld   (D5CA),a
ROM5:4B5E 18 0C            jr   4B6C
ROM5:4B60 3E 01            ld   a,01
ROM5:4B62 EA CB D5         ld   (D5CB),a
ROM5:4B65 18 05            jr   4B6C
ROM5:4B67 3E 01            ld   a,01
ROM5:4B69 EA CC D5         ld   (D5CC),a
ROM5:4B6C 3E 00            ld   a,00
ROM5:4B6E EA 14 D4         ld   (D414),a
ROM5:4B71 FA 84 D5         ld   a,(D584)
ROM5:4B74 EA 97 D4         ld   (D497),a
ROM5:4B77 FA 14 D4         ld   a,(D414)
ROM5:4B7A CD F9 43         call 43F9
ROM5:4B7D FA 77 D4         ld   a,(D477)
ROM5:4B80 EA 15 D4         ld   (D415),a
ROM5:4B83 AF               xor  a
ROM5:4B84 EA 5A D4         ld   (D45A),a
ROM5:4B87 3E 2C            ld   a,2C
ROM5:4B89 EA 00 D4         ld   (D400),a
ROM5:4B8C C9               ret
I didn't comment much here because I didn't fully understand it. But for Crypto's personality at least, it seems to have this probability of being normal: (2*FD+55)/256. For a Denjuu with 0 FD, that means you have a 55/256 (21.6%) chance of being able to select the move yourself, while for a Denjuu with 100 FD, the chance of the Denjuu acting normal is 255/256 (99.6%). Yes, this falls victim to the 99.6 rule: If the random number comes up 255, then Crypto does whatever the heck it wants. Sound familiar? (And yes, I checked this myself.)

So... that's all I have. It's a start, at least. Now we know how the game generates random numbers, and the probabilities of certain things, like wild Denjuu species/level/personality, and we kind of know the probability of escaping and FD-related things. Eventually I will look more into everything else, unless someone gets to it first!

But, I hope this is useful.
Post Reply