Wednesday, November 16, 2011

Additional optimism for AI script separation

I was thinking about it this morning (as I was trying to get my daughter back to sleep) that instead of actually running byte-per-byte comparisons on AI scripts that have the same lengths, I can just generate CRCs per script as they load! That way I can compare the CRCs with the lengths to determine if two scripts are identical The possibility of two different scripts with the same length and the same CRC is so close to 0 that logic states it's impossible. As a result, that will turn an "n log n" function into a "< 3n" function! With over a thousand unique scripts that's a vast improvement!

EDIT:
Success! Let me give you an idea of what this does now. In the following list, each listed actor is unique. The entries below the actor's name indicate that there is an AI script present in that section and the number next to that section is a unique script ID assigned as it is read in order:

Mystery Ninja
0: 127
1: 128
3: 129
15: 130

Mystery Ninja
0: 127
1: 128
3: 131
15: 130

Mystery Ninja
0: 127
1: 132
3: 133
15: 130

Mystery Ninja
0: 127
1: 132
3: 134
15: 130

Mystery Ninja
0: 127
1: 132
3: 135
15: 130

Mystery Ninja
0: 127
1: 132
3: 136
15: 130

So with those six actors and 24 active script blocks, there are only 10 unique scripts between them! The init and custom event 8 blocks are all identical and most of the main scripts are the same. The only thing that uniquely identifies them is the "death counter" which will set the level that Yuffie joins the party at. This is just the kind of thing I'm trying to solve. Instead of wasting space copying three identical scripts twice. This way we can create more intricate behaviors and counters while maintaining synchronicity between all six (or a set of six) without having to modify all six.
Slick, right? :)

Friday, November 4, 2011

AI Blocks not so static....

So this just occurred to me. The pointers to AI scripts are just pointers to a script that gets run until it hits the 73h byte, right? Well it seems to me that this is a grossly underused system. What it does right now is have pointers to the pointers per enemy per script with the actual scripts in between:

[Enemy 0's AI][Enemy 1's AI][Enemy 2's AI][Enemy 0's Sections][Enemy 0's Scripts][Enemy 1's Sections][Enemy 1's Scripts][Enemy 2's Sections][Enemy 2's Scripts]

That seems pretty wasteful. You could do it this way as it is without modification or worry that it'll blow up:

[Enemy 0's AI][Enemy 1's AI][Enemy 2's AI][Enemy 0's Sections][Enemy 1's Sections][Enemy 2's Sections][All Scripts]

What's the advantage? SHARED AI SCRIPTS!! Let's say that we want Enemy 0 and Enemy 1 to behave the same way. They have a 40% chance of not attacking every other turn or so. Why not let their main scripts point to the same script? Oh, but now you say "but their attacks will be different. Unless they're using the same attack that will be useless!" No it won't. Consider this as a script:

0x000: 12 00A0
0x003: 61 0131
0x006: 72 000F
0x009: 12 00A0
0x00C: 61 0146
0x00F: 90
0x010: 60 20
0x013: 02 00A0
0x015: 92

Starting from the beginning we're loading attack ID 0131h and executing it, but starting at 009 we're loading attack 0146h and executing it! This can pose a problem for jumps, but if you pre-load attack variables in the init scripts then you can easily share a more complicated Main between two actors!

This can also be used to share counter-attack behaviors (like running) and a few other things.

Man, I'm awesome. B)

Whoops. I forgot to finish this thought.
One thing I can think of right now that can be changed is that stupid "A Chocobo!!" init script that's shared by EVERY enemy that is in a formation with a Chocobo. They're all the same script so they could all share it and free up space for more complicated script behaviors.

As a result, I was thinking of adding another category to the list of things this handles. Adding AI as a section would be great. That requires naming each one and comparing them one-by-one. That takes time. There are some easy ways to shave off this time like comparing lengths first. There can never be more than 28,672 unique AI scripts contained in the scene.bin and they can have wildly different lengths. The ones with different lengths are obviously not a match.

Also, this would be super difficult and confusing to have to load the scene.bin each time and parse through it like this. I could have PrCMDI create it's own database save with everything already parsed out that it could load much faster than the scene.bin could. You could save as this database (which could be legally freely distributed) and just export to a scene.bin that could be used by the game.

Yep, still awesome! B)