[PSX/PC] AI Script compiler - Conformer (v0.2)

  • Thread starter Thread starter ficedula
  • Start date Start date
Status
Not open for further replies.
F

ficedula

Guest
v0.2 download: http://www.ficedula.co.uk/Conformer/Conformer_0_2.zip


Old versions:

v0.1 download: http://www.ficedula.co.uk/Conformer/Conformer_0_1.zip (you will need an up to date version of the .NET framework installed also).

This is an initial release: there's many things missing I'd like to add but enough is working now for it to be functional and for me to gather some feedback, so, here you go.

Conformer is essentially a script compiler for the AI scripts. (It doesn't replace Proud Clod - in fact you currently need Proud Clod to make any good use of it). The idea is that rather than writing AI scripts in the raw bytecode you can write them in a vaguely friendly scripting language and Conformer will compile your textual script down into the bytecode FF7 uses.

Here's a very simple example:

Code: [Select]
Code:
Import commonconst word ATT_BODYBLOW := $0172const word ATT_FANG := $0189function AI.Main: void Targets := PickRandomBit(Enemies) if (Random() mod 2) = 0 then         Call Perform(ENEMY_ATTACK, ATT_FANG) else         Call Perform(ENEMY_ATTACK, ATT_BODYBLOW) end ifend function
Obviously this is pretty simple and the sort of thing you could code in the bytecode manually but it's a bit nicer to do it this way ;)

Here's something a bit more complex:

Code: [Select]
Code:
Import commonconst word ATT_BODYBLOW := $0172function AI.Main: void if LoadStats(Me, StatCurrentHP) < (LoadStats(Me, StatMaxHP) / 2) then  Targets := PickRandomBit(FindLargest(LoadStats(Enemies, StatCurrentHP))) else  Targets := PickRandomBit(Allies) end if Call Perform(ENEMY_ATTACK, ATT_BODYBLOW)end function
I can't see why you would implement a script like this ;) but it's a good example of the language. In this case, it loads the current creature's HP, and if it's less than half of their maximum HP, it loads the HP of all the enemies, finds which of them has the most, and picks a random one of those to target. Otherwise it targets a random ally.

How to actually use it...:

guide.png


You type your script into location (1). (You can load, save, etc. scripts from the menu like normal.)

Once you've entered your script, pick one of the AI functions you've written (e.g. AI.Main) from the list (2).

Then click Compile (3).

Either it'll work, or it'll show you errors in the listbox (4), in which case you need to fix the errors first!

If it works, it'll output the bytecode in area (5), in three formats: plain binary, commented binary explaining what each block of bytecode is doing, and (most usefully) in the text format Proud Clod expects for you to paste into the AI editor. Since Conformer doesn't have an option yet to edit the scene.bin files that's how you'll want to get your AI into the actual game.

A language reference is available from the Help menu or here: http://www.ficedula.co.uk/Conformer/0.1/Language.html or off course post questions here!

I have quite a few planned features to add; direct write support into scene.bin is an obvious one, the bytecode it produces could be optimised further, and some other things, but requests are also welcome.

Cheers!
 
Last edited:
Also, an additional example that I forget to mention above about using global variables (that persist from one script call to the next):

Code: [Select]
Code:
Import commonconst word ATT_BODYBLOW := $0172byte modefunction AI.Main: void if mode = 0 then  Targets := Me else if mode = 1 then  Targets := PickRandomBit(FindLargest(LoadStats(Enemies, StatCurrentHP))) else if mode = 2 then  Targets := PickRandomBit(Allies) end if Call Perform(ENEMY_ATTACK, ATT_BODYBLOW) mode := (mode + 1) mod 3end function
In this case the 'mode' variable persists from one function call to the next - we cycle it through 3 values so the enemy's behaviour effectively loops every 3 actions.
 
Last edited:
Let me know if there's any script PrC doesn't like. Its AI script editor is undoubtedly the shoddiest piece of it.
 
Don't forget qgears team have this:

https://github.com/paulsapps/SUDM

Which will eventually support disassembly of all FF7 scripts (AI/Field,World whatever else). Creating an assembler (and then a generic compiler) shouldn't be too much more work..

/plug
 
Interesting, but not really useful for me since I'm not intending to disassemble any of the existing AI (most of it is so simple there's no point).
 
This is a great piece of work that I think the community has been wanting for quite some time now. I did have the idea to do something along these lines, but it was a daunting prospect to write a compiler, and to be honest, I don't think I'd have ever got around to it.

Now I can write AI scripts as I like, without the ardour of manually scripting, debugging and editing. I can write scripts in a high level language, keep them in version control, and re-compile scripts as and when the compiler improves. This is absolutely the way we should be doing modding - not scrabbling around with binary files. Such an approach just isn't scalable in a large project.

I do have a couple questions, though:
1. How confident are you in the output of the compiler? Would you say it's fairly reliable?
2. Is there a reference for some of those inbuilt functions, like 'LoadStats()'?

...And once again - well done.
 
Last edited:
Update: Ficedula's site is currently down, but you can access a cached version of the language specification at http://webcache.googleusercontent.com/search?q=cache:http://www.ficedula.co.uk/Conformer/0.1/Language.html

I've also sent a PM to the OP to see if they can get the server up and running again.

Also, RE: a reference for common functions like LoadStats: there's a text file in the package (common.conformer) full of function declarations. Here's its text:

Code: [Select]
Code:
#Some common battle values that you'll probably wantconst word^ Enemies := $20A0const word^ ActiveEnemies := $20B0const word^ Targets := $2070const word^ Allies := $2080const word^ ActiveAllies := $2090const word^ Me := $2060const word^ AllCreatures := $2050const word^ StatCurrentMP := $4140const word^ StatMaxMP := $4150const dword^ StatCurrentHP := $4160const dword^ StatMaxHP := $4180#Kinds of attackconst byte ENEMY_ATTACK := $20raw function PickRandomBit(word w): dword $82end functionraw function Random: Word $81end functionraw function Perform(byte kind, word ability): void  #Note attack kind FIRST, not ability code! $92end functionraw function LoadStats(word chars, dword stat): dword $80end functionraw function FindLargest(dword stats): dword $84end functionraw function FindSmallest(dword stats): dword $85end function
I assume packages can just be added to the root of the Conformer directory and called in the same way as Common using the 'import' keyword.

I also notice that opcodes can be inlined by just adding them as hex numbers.
 
Last edited:
Thanks a lot for this, I can't wait to try it out! I've always wanted to create better/more intelligent AI scripts for some enemies, and so far I've used Proud Clod to do it. This will help tremendously!
 
You stole my idea, I was planning on making one (in about 20 years or so when I got time lol).

Looking forward to the development of this!  :D
 
New version v0.2: http://www.ficedula.co.uk/Conformer/Conformer_0_2.zip

Main new feature is that there's effectively real time debugging of the scripts while FF7 is running.

To use this:

-Copy Conformer.debug.dll into your FF7\DLL_in folder (so, you need to be running the appropriate driver/setup for DLL_in to work!)
-Compile your AI script making sure "Compile in debug mode" is ticked
-Insert the AI script into the scene.bin using Proud Clod
-Run FF7
-Click the 'Debug' button, which will pop up the debugger interface for the current script;

debugger.png


Once the debugger is ready you can set a breakpoint by clicking in the left hand margin (see line 9 in the screenshot). When the AI script gets to that point, it'll pause. You can see the value of any variables in the right hand window, and step through the code using the debug menu (there are shortcuts for step / continue). The current line is highlighted with the shaded background.

Still kind of experimental, but it works on the test script, so it seems basically usable...

Note: Every time you compile a script, it gets a new unique ID and the debugger requires the IDs to match in order to debug it. So, once you've inserted a script into the scene.bin don't compile that script again as you'll then lose the ability to debug it. I'll be making this better in the next version.
 
Status
Not open for further replies.
Back
Top