Author Topic: [FF8] Jsm script formatter  (Read 1908 times)

Albeoris

  • *
  • Posts: 72
    • View Profile
    • FFRTT
[FF8] Jsm script formatter
« on: 2019-05-28 00:59:33 »
As part of the OpenVIII project, I wrote a formatter for game scripts.

The idea of pseudo-code from Deling is taken as a basis.
Deling sample:
Spoiler: show
Code: [Select]
if 256_uword == 612 begin
ucoff()
rcanimekeep(5, 25, 1)
amesw(0, 42, 160, 8)
aask(0, 43, 0, 4, 0, 4, 160, 8)
animesync()
if temp_0 == 0 begin
rcanimekeep(5, 100, 72)
1027_ubyte = 0
squall.houkoku(5, EW)
animesync()
ranimekeep(4)
amesw(0, 45, 160, 8)
else if temp_0 == 1 begin
1027_ubyte = 1
squall.houkoku(5, EW)
animesync()
rcanimekeep(5, 72, 25)
amesw(0, 47, 160, 8)
animesync()
canimekeep(5, 100, 72)
ranimekeep(4)
amesw(0, 48, 160, 8)
1027_ubyte = 2
squall.houkoku(5, EW)
animesync()
rcanimekeep(6, 128, 1)
amesw(0, 50, 160, 8)
animesync()
rcanimekeep(6, 150, 128)
else if temp_0 == 2 begin
1027_ubyte = 3
squall.houkoku(5, EW)
animespeed(32)
rcanimekeep(7, 72, 24)
amesw(0, 53, 160, 8)
animesync()
animespeed(16)
rcanimekeep(5, 72, 20)
amesw(0, 54, 160, 8)
animesync()
canimekeep(5, 100, 72)
ranimekeep(4)
amesw(0, 55, 160, 8)
animesync()
rcanimekeep(6, 128, 1)
amesw(0, 56, 160, 8)
animesync()
canimekeep(6, 150, 128)
rcanimekeep(5, 72, 1)
amesw(0, 57, 160, 8)
animespeed(32)
animesync()
animespeed(16)
rcanimekeep(7, 50, 24)
amesw(0, 58, 160, 8)
animesync()
rcanimekeep(7, 100, 50)
else if temp_0 == 3 begin
1027_ubyte = 4
squall.houkoku(5, EW)
animesync()
canimekeep(5, 100, 72)
rcanimekeep(6, 20, 1)
amesw(0, 60, 160, 8)
animesync()
rcanimekeep(6, 105, 20)
amesw(0, 61, 160, 8)
animesync()
rcanimekeep(6, 128, 105)
amesw(0, 62, 160, 8)
animesync()
canimekeep(6, 150, 128)
rcanimekeep(5, 72, 1)
amesw(0, 64, 160, 8)
animespeed(32)
animesync()
animespeed(16)
rcanimekeep(7, 50, 24)
amesw(0, 65, 160, 8)
animesync()
animespeed(32)
canimekeep(7, 100, 50)
animespeed(16)
rcanimekeep(4, 80, 1)
amesw(0, 66, 160, 8)
animesync()
rcanimekeep(4, 105, 80)
else if temp_0 == 4 begin
1027_ubyte = 5
squall.houkoku(5, EW)
animesync()
rcanimekeep(5, 100, 72)
amesw(0, 68, 160, 8)
animesync()
ranimekeep(4)
amesw(0, 69, 160, 8)
else
end
ucon()
animesync()
end
ret(8)


My sample:
Spoiler: show
Code: [Select]
    public void Talk()
    {
        // ScriptId: 52
        if(((UInt16)G[256] == 612))
        {
            IGameplayService.IsUserControlEnabled = false; // UCOFF
            this.Animation.Play(animationId: 5, firstFrame: 1, lastFrame: 25); // RCANIMEKEEP

            // Headmaster Cid
            // “What shall we talk about?”
            await IMessageService.ShowDialog(channel: 0, messageId: 42, posX: 160, posY: 8); // AMESW

            //☞ (I want to make a report)
            //   (The real meaning of SeeD)
            //   (About Sorceress Edea)
            //   (About Master NORG)
            //☜ (About what to do next)
            await IMessageService.ShowDialog(channel: 0, messageId: 43, firstLine: 0, lastLine: 4, beginLine: 0, cancelLine: 4, posX: 160, posY: 8); // AASK
            await this.Animation.Wait(); // ANIMESYNC
            if((R0 == 0))
            {
                this.Animation.Play(animationId: 5, firstFrame: 72, lastFrame: 100); // RCANIMEKEEP
                G[1027] = (Byte)0;
                REQEW(priority: 5, GetObject<squall>().houkoku());
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 4); // RANIMEKEEP

                // Headmaster Cid
                // “No, no.
                //  It’s not necessary.”
                // “I can guess what must’ve
                //  happened.”
                await IMessageService.ShowDialog(channel: 0, messageId: 45, posX: 160, posY: 8); // AMESW
            }
            else if((R0 == 1))
            {
                G[1027] = (Byte)1;
                REQEW(priority: 5, GetObject<squall>().houkoku());
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 5, firstFrame: 25, lastFrame: 72); // RCANIMEKEEP

                // Headmaster Cid
                // “SeeD is SeeD.  The elite
                //  mercenary force of {Term Balamb} Garden.”
                await IMessageService.ShowDialog(channel: 0, messageId: 47, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                await this.Animation.Play(animationId: 5, firstFrame: 72, lastFrame: 100); // CANIMEKEEP
                this.Animation.Play(animationId: 4); // RANIMEKEEP

                // Headmaster Cid
                // “Hmmm, do you know
                //  something about SeeD?”
                await IMessageService.ShowDialog(channel: 0, messageId: 48, posX: 160, posY: 8); // AMESW
                G[1027] = (Byte)2;
                REQEW(priority: 5, GetObject<squall>().houkoku());
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 6, firstFrame: 1, lastFrame: 128); // RCANIMEKEEP

                // Headmaster Cid
                // “SeeD will defeat the sorceress.
                //  The Garden will train SeeD members.”
                // “The many missions around the world
                //  are only training for the final
                //  battle against the sorceress.”
                // “But now that the sorceress has become a
                //  major threat, our true mission
                //  has begun.”
                await IMessageService.ShowDialog(channel: 0, messageId: 50, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 6, firstFrame: 128, lastFrame: 150); // RCANIMEKEEP
            }
            else if((R0 == 2))
            {
                G[1027] = (Byte)3;
                REQEW(priority: 5, GetObject<squall>().houkoku());
                this.Animation.FPS = 64; // ANIMESPEED
                this.Animation.Play(animationId: 7, firstFrame: 24, lastFrame: 72); // RCANIMEKEEP

                // Headmaster Cid
                // “You’re quite right...”
                await IMessageService.ShowDialog(channel: 0, messageId: 53, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.FPS = 32; // ANIMESPEED
                this.Animation.Play(animationId: 5, firstFrame: 20, lastFrame: 72); // RCANIMEKEEP

                // Headmaster Cid
                // “She had been a sorceress since childhood.
                //  I married her, knowing that.”
                await IMessageService.ShowDialog(channel: 0, messageId: 54, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                await this.Animation.Play(animationId: 5, firstFrame: 72, lastFrame: 100); // CANIMEKEEP
                this.Animation.Play(animationId: 4); // RANIMEKEEP

                // Headmaster Cid
                // “We were happy.
                //  We worked together, the two of us.
                //  We were very happy.”
                await IMessageService.ShowDialog(channel: 0, messageId: 55, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 6, firstFrame: 1, lastFrame: 128); // RCANIMEKEEP

                // Headmaster Cid
                // “One day, Edea began talking about
                //  building the Garden and training SeeD.”
                // “I became obsessed with that plan.  But
                //  I was very concerned with SeeD’s goal,
                //  that one day SeeD might fight Edea...”
                await IMessageService.ShowDialog(channel: 0, messageId: 56, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                await this.Animation.Play(animationId: 6, firstFrame: 128, lastFrame: 150); // CANIMEKEEP
                this.Animation.Play(animationId: 5, firstFrame: 1, lastFrame: 72); // RCANIMEKEEP

                // Headmaster Cid
                // “She laughed and told me
                //  that would never happen.”
                await IMessageService.ShowDialog(channel: 0, messageId: 57, posX: 160, posY: 8); // AMESW
                this.Animation.FPS = 64; // ANIMESPEED
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.FPS = 32; // ANIMESPEED
                this.Animation.Play(animationId: 7, firstFrame: 24, lastFrame: 50); // RCANIMEKEEP

                // Headmaster Cid
                // “However...”
                await IMessageService.ShowDialog(channel: 0, messageId: 58, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 7, firstFrame: 50, lastFrame: 100); // RCANIMEKEEP
            }
            else if((R0 == 3))
            {
                G[1027] = (Byte)4;
                REQEW(priority: 5, GetObject<squall>().houkoku());
                await this.Animation.Wait(); // ANIMESYNC
                await this.Animation.Play(animationId: 5, firstFrame: 72, lastFrame: 100); // CANIMEKEEP
                this.Animation.Play(animationId: 6, firstFrame: 1, lastFrame: 20); // RCANIMEKEEP

                // Headmaster Cid
                // “He is from the Shumi tribe.
                //  A black sheep of the tribe, one might say.”
                await IMessageService.ShowDialog(channel: 0, messageId: 60, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 6, firstFrame: 20, lastFrame: 105); // RCANIMEKEEP

                // Headmaster Cid
                // “We met while I was running around
                //  trying to find funds to build the Garden.”
                // “He became interested in building
                //  the Garden, and we hit it off.
                //  Thanks to his funding, it was completed.”
                await IMessageService.ShowDialog(channel: 0, messageId: 61, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 6, firstFrame: 105, lastFrame: 128); // RCANIMEKEEP

                // Headmaster Cid
                // “However, we needed an enormous
                //  amount of funds to run the Garden.”
                // “So we began dispatching SeeDs
                //  around the world as a means
                //  of supporting the Garden.”
                await IMessageService.ShowDialog(channel: 0, messageId: 62, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                await this.Animation.Play(animationId: 6, firstFrame: 128, lastFrame: 150); // CANIMEKEEP
                this.Animation.Play(animationId: 5, firstFrame: 1, lastFrame: 72); // RCANIMEKEEP

                // Headmaster Cid
                // “NORG’s idea was
                //  right on the money.”
                // “An enormous amount of capital
                //  began flowing into the Garden.”
                await IMessageService.ShowDialog(channel: 0, messageId: 64, posX: 160, posY: 8); // AMESW
                this.Animation.FPS = 64; // ANIMESPEED
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.FPS = 32; // ANIMESPEED
                this.Animation.Play(animationId: 7, firstFrame: 24, lastFrame: 50); // RCANIMEKEEP

                // Headmaster Cid
                // “And the Garden began to change.”
                // “Lost sight of our high ideals,
                //  the truth was covered up...”
                await IMessageService.ShowDialog(channel: 0, messageId: 65, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.FPS = 64; // ANIMESPEED
                await this.Animation.Play(animationId: 7, firstFrame: 50, lastFrame: 100); // CANIMEKEEP
                this.Animation.FPS = 32; // ANIMESPEED
                this.Animation.Play(animationId: 4, firstFrame: 1, lastFrame: 80); // RCANIMEKEEP

                // Headmaster Cid
                // “That’s probably enough.”
                // “In the end, it was my fault,
                //  for giving up control.”
                await IMessageService.ShowDialog(channel: 0, messageId: 66, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 4, firstFrame: 80, lastFrame: 105); // RCANIMEKEEP
            }
            else if((R0 == 4))
            {
                G[1027] = (Byte)5;
                REQEW(priority: 5, GetObject<squall>().houkoku());
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 5, firstFrame: 72, lastFrame: 100); // RCANIMEKEEP

                // Headmaster Cid
                // “We must stop
                //  drifting around soon...”
                await IMessageService.ShowDialog(channel: 0, messageId: 68, posX: 160, posY: 8); // AMESW
                await this.Animation.Wait(); // ANIMESYNC
                this.Animation.Play(animationId: 4); // RANIMEKEEP

                // Headmaster Cid
                // “I only hope that we can get things
                //  back to the way they were.”
                await IMessageService.ShowDialog(channel: 0, messageId: 69, posX: 160, posY: 8); // AMESW
            }
            else if((R0 == 0))
            {
                // do nothing
            }
            IGameplayService.IsUserControlEnabled = true; // UCON
            await this.Animation.Wait(); // ANIMESYNC
        }
        return IRET(8);
    }


Just keep in mind that I didn't intend to write a replacement for Deling. We do different things. Deling allows you to edit game scripts, but my task is to make the code understandable for humans.
This formatting is done for only a third of instructions. Will we finalize it - I don't know yet. But it helped a lot in understanding the code in order to implement it in a new engine.

If it is useful to someone - use it. :)
For me it was an interesting experience. I plan to add support for normal scripts in FF9.

There is all of formatted field scripts:
https://yadi.sk/d/MMuojnn3VZoXDg
« Last Edit: 2019-05-28 01:01:27 by Albeoris »