øAslickproductions.org/forum/index.php?PHPSESSID=5f0fck550j2m4m2fpbtkj2vkm1&topic=2190.15e:/My Web Sites/Slick Productions - FFIV Message Board/slickproductions.org/forum/index1875-2.htmlslickproductions.org/forum/index.php?PHPSESSID=5f0fck550j2m4m2fpbtkj2vkm1&board=17.40e:/My Web Sites/Slick Productions - FFIV Message Board/slickproductions.org/forum/index1875-2.html.zxS9h^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÈ@Pe¼OKtext/htmlISO-8859-1gzip@øÕ¼ÿÿÿÿÿÿÿÿWed, 11 Mar 2020 01:21:48 GMT0ó°° ®0®P®€§²ð®R9h^ÿÿÿÿÿÿÿÿ%¼ Amusing Bit of Timer Code

Author Topic: Amusing Bit of Timer Code  (Read 2899 times)

Squall

  • Dark Dragon
  • *
  • Posts: 486
    • View Profile
Re: Amusing Bit of Timer Code
« Reply #15 on: April 19, 2016, 02:59:46 AM »
I'm not sure, there might be difference between GBA/SNES (although I doubt its something major) but:
spellpower as you call it ( spellpower + caster level/4 - defender level/4 + misc)

in SNES it is:
Code: [Select]
Final/Timer Duration := 2 * SpellDuration + (Attacker Level / 4) - (Target Level / 4)
- SpellDuration is 7 bits of P2 ($58)
- Target Level/4 is calculated only if bit7 of P2 is not set

If somebody is interested, the values that x0_000 describe in SNES are here (I have corrected Tseng's decompilation because it had HUGE error in this part:
Code: [Select]
JMP Table
C2/254A: 72 25        $2572        Spell Duration
C2/254C: 76 25        $2576        120
C2/254E: 79 25        $2579        Attacker's Vitality + 20
C2/2550: 79 25        $2579        Attacker's Vitality + 20
C2/2552: 72 25        $2572        Spell Duration
C2/2554: 84 25        $2584        120
C2/2556: 72 25        $2572        Spell Duration
C2/2558: 87 25        $2587        49
C2/255A: 72 25        $2572        Spell Duration
C2/255C: 8A 25        $258A        180 - Attacker's Magic / 2
C2/255E: 72 25        $2572        Spell Duration
C2/2560: 9A 25        $259A        180
C2/2562: 9D 25        $259D        10
C2/2564: 9D 25        $259D        10
C2/2566: A0 25        $25A0        110 - Attacker's Magic
C2/2568: A0 25        $25A0        110 - Attacker's Magic
C2/256A: AF 25        $25AF        30
C2/256C: AF 25        $25AF        30
C2/256E: B2 25        $25B2        Spell Duration - Attacker's Magic / 2
C2/2570: C3 25        $25C3        120 - Attacker's Magic / 2

Duration = Spell Duration
C2/2572: AD D8 3E     LDA $3ED8
C2/2575: 60           RTS

Duration = 120
C2/2576: A9 78        LDA #$78
C2/2578: 60           RTS

Duration = Attacker's Vitality + 20
C2/2579: 18           CLC
C2/257A: AD E3 7B     LDA $7BE3
C2/257D: 69 14        ADC #$14
C2/257F: 90 02        BCC $2583
C2/2581: A9 FF        LDA #$FF
C2/2583: 60           RTS

Duration = 120
C2/2584: A9 78        LDA #$78
C2/2586: 60           RTS

Duration = 49
C2/2587: A9 31        LDA #$31
C2/2589: 60           RTS

Duration = 180 - Attacker's Magic Power / 2
C2/258A: AD E4 7B     LDA $7BE4
C2/258D: 4A           LSR
C2/258E: 85 0E        STA $0E
C2/2590: 38           SEC
C2/2591: A9 B4        LDA #$B4
C2/2593: E5 0E        SBC $0E
C2/2595: B0 02        BCS $2599
C2/2597: A9 01        LDA #$01
C2/2599: 60           RTS

Duration = 180
C2/259A: A9 B4        LDA #$B4
C2/259C: 60           RTS

Duration = 10
C2/259D: A9 0A        LDA #$0A
C2/259F: 60           RTS

Duration = 110 - Attacker's Magic Power
C2/25A0: 38           SEC
C2/25A1: A9 6E        LDA #$6E
C2/25A3: ED E4 7B     SBC $7BE4
C2/25A6: 90 04        BCC $25AC
C2/25A8: C9 1E        CMP #$1E
C2/25AA: B0 02        BCS $25AE
C2/25AC: A9 1E        LDA #$1E
C2/25AE: 60           RTS

Duration = 30
C2/25AF: A9 1E        LDA #$1E
C2/25B1: 60           RTS

Duration = Spell Duration - Attacker's Magic Power / 2
C2/25B2: AD E4 7B     LDA $7BE4
C2/25B5: 4A           LSR
C2/25B6: 85 0E        STA $0E     (Magic Power/2)
C2/25B8: 38           SEC
C2/25B9: AD D8 3E     LDA $3ED8   (Status Duration = Status Duration - (Magic Power/2))
C2/25BC: E5 0E        SBC $0E
C2/25BE: B0 02        BCS $25C2
C2/25C0: A9 01        LDA #$01
C2/25C2: 60           RTS

Duration = 120 - Attacker's Magic Power / 2
C2/25C3: AD E4 7B     LDA $7BE4
C2/25C6: 4A           LSR
C2/25C7: 85 0E        STA $0E
C2/25C9: 38           SEC
C2/25CA: A9 78        LDA #$78
C2/25CC: E5 0E        SBC $0E
C2/25CE: B0 02        BCS $25D2
C2/25D0: A9 01        LDA #$01
C2/25D2: 60           RTS 

Edit 1> It seems your 11082  is Attacker's Magic Power ($7BE4). Also in SNES Doom is 49 not 59 ...
Edit 2> BTW how Doom work? Obviously you dont die in 49 ticks ... maybe every 49 ticks you get Coundown -1 (which is initialized by 30)
Edit 3> I have replaced Tseng decompilation and added more comments
Edit 4> x0_000, all the entries it the Jump table are pared. In SNES that depend on $3ED7. It has value 0 or 1 and I think it shows who is the target: char or monster
« Last Edit: April 19, 2016, 04:42:47 AM by Squall »

x0_000

  • Siren
  • *
  • Posts: 72
    • View Profile
Re: Amusing Bit of Timer Code
« Reply #16 on: April 19, 2016, 01:18:27 PM »
You're right, it's 49. I did a quick check and it looks like the Cursed Ring sets the Doom counter at 49, and peeking at the RAM it counts down at the same rate. The Doom spell is correct at 30, though, so it looks like something else handles its value.

And yeah, I don't remember what the actual spellpower calculation is off the top of my head, I just know it's a magic value modified by the levels of the actors involved.

Edit: Looks like I missed one value (probably Doom - spellpower), the previous notes are updated. I know what the pairs are for now, it's whether the status is caused by a spell or through an equipment (e.g. Cursed Ring.) My gut feeling also says those values should be Victim's <stat>, not Attacker's <stat> since there is no Attacker for statuses caused by items.
« Last Edit: April 19, 2016, 01:24:02 PM by x0_000 »

Squall

  • Dark Dragon
  • *
  • Posts: 486
    • View Profile
Re: Amusing Bit of Timer Code
« Reply #17 on: April 19, 2016, 02:30:43 PM »
Edit: Looks like I missed one value (probably Doom - spellpower), the previous notes are updated. I know what the pairs are for now, it's whether the status is caused by a spell or through an equipment (e.g. Cursed Ring.) My gut feeling also says those values should be Victim's <stat>, not Attacker's <stat> since there is no Attacker for statuses caused by items.
You are most likely right. My description for 'Attacker' comes with plain substitution of Tseng's variable list ... but as I have already witness there are (many) mistakes. The fact that an item could bear a status mean that 'Attacker' should not play a role. That was the reason for me asking couple of days ago :)

LightPhoenix

  • FF5 Hacker
  • *
  • Posts: 130
    • View Profile
Re: Amusing Bit of Timer Code
« Reply #18 on: April 23, 2016, 05:32:42 PM »
There are a bunch of areas of the available decomp that get thrown off by large data structures or the occasional missed SEP/REP #20.

I've never worked with the FF5A code (or any GBA game before) but the two tables look to be laid out mostly the same.  Have either of you looked looked at the available RAM space on the GBA?  I'd consider moving to it if it ends up being easier to add things (ie, if there's more available RAM).

FF5's timer stuff is mostly laid out in blocks of twelve sets of eleven bytes: one set of eleven timer bytes for each character, in order.  From what I've gathered (all for SNES):

7E/3CF1: Timer Status Flags (132b) - 01 for "on", 00 for "off", 80 for "ending" (really 81, since it's still considered on while ending)
7E/3D75: Timer Remaining Duration (132b) - self explanatory, decreased by one for each timer decrement duration, see below
7E/3DF9: Timer Initial Duration (132b) - Used by Poison and Regen to reset statuses that "tick"

7E/3ED9: Timer Decrement Duration (11b) - Certain timers do not decrement every frame.  These values are held in D1/2976, and are [00 02 04 0E 01 00 00 01 00 00 00].  This timer gets decremented, and if it is zero, the actual remaining duration gets decremented.
7E/3EE4: Process Timer Flag (11b) - Set when the decrement timer is zero; true when processing, false when not needed

7E/3E88: Process Ending Timer Flag (11b) - Set when any creature's timer reached zero.  The code only handles ending one creature per status each frame.
7E/3EB7: Creature Timer Ending (11b) - Set to whichever creature number's timer is ending this frame.

7E/3E93: Random Creature List (12b) - A randomized list of each creature position (0-B), generated when battle starts at C2/1FD2.
7E/3E7D: Creature List Counter (11b) - A counter used to rotate through each creature in the list above.

There's also a set at 7E/3E9F that I haven't yet figured out.

Quote
BTW how Doom work? Obviously you dont die in 49 ticks ... maybe every 49 ticks you get Coundown -1 (which is initialized by 30)

Good guess!  It only gets decremented every 15 frames, so it's really 15 * 30 for the duration.
« Last Edit: April 23, 2016, 05:37:56 PM by LightPhoenix »

Squall

  • Dark Dragon
  • *
  • Posts: 486
    • View Profile
Re: Amusing Bit of Timer Code
« Reply #19 on: April 26, 2016, 01:48:41 AM »
Hehe when I said that such way of implementation will require a lot of memory I didnt know that it require even more. Excellent exposition LightPhoenix!

Just to finish what we were discussing with x0_000. I started to dig up and write my own coments on Tseng C2 dump and picture started to reveal itself. As our 'guts & nuts' have suggested, all stats used are against Targets value. In SNES it uses $48 as participant index, which is the Target, not the Attacker.
What is interesting to me was that many of the attacks that enemy use that inflict status (on timer) are 'item' based ($3ED7 is initialized with 1), like Grand-Cross.

P.S. LightPhoenix I would suggest instead of adding a new timer to replace an existing one. This way all the code needed to implement is there, you just need to write what to do when timer reach 0. If I had to choose I would replace Doom.

Praetarius5018

  • Vargas
  • *
  • Posts: 88
    • View Profile
Re: Amusing Bit of Timer Code
« Reply #20 on: May 09, 2016, 05:37:48 AM »
I've done this before for some CT code, but I came across this gem in the FF5 timer code:

Code: [Select]
C2/2085: A5 0C        LDA $0C (Are we looking at Stop?)
C2/2087: D0 00        BNE $2089 (uhhhh)
C2/2089: E6 08        INC $08 (return TRUE)

I've come across similar strange codes and if what I've read is correct, this form of branch to pad two "do nothing" bytes is minimal cheaper than 2x NOP.
BNE supposedly costs 2 CPU cycles total, 1 NOP does also, so 2 NOP are more expensive.
BRA would be inbetween those two options.
Does it matter in the grand scheme of things? Probably not.

Squall

  • Dark Dragon
  • *
  • Posts: 486
    • View Profile
Re: Amusing Bit of Timer Code
« Reply #21 on: May 09, 2016, 02:58:29 PM »
Hehe that would suggest that somebody did fine tuning and just happen to need 2 cycles :D
Although possible its highly unlikely. Seen how bad or not optimize code is in some places ... even I with my rusty 65x02 knowledge would do it better atm. For example Row command, the code for changing the row is just terrible I cold do it with just 3 instruction, while they isolate high bit and do plenty of instructions there just to invert it.

While reading the asm code I have the constant feeling they have used a higher level language that have compiled some of these 'jewels' :D