Author Topic: [PSX/PC] AI Script compiler - Conformer (v0.2)  (Read 12209 times)

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
[PSX/PC] AI Script compiler - Conformer (v0.2)
« on: 2015-02-15 16:18:32 »
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]
Import common

const word ATT_BODYBLOW := $0172
const word ATT_FANG := $0189

function 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 if
end 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]
Import common

const word ATT_BODYBLOW := $0172

function 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...:



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 Edit: 2018-04-24 18:33:33 by Covarr »

Roden

  • *
  • Posts: 125
    • View Profile
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #1 on: 2015-02-15 16:59:15 »
That's just... brilliant :)

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #2 on: 2015-02-15 18:15:35 »
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]
Import common

const word ATT_BODYBLOW := $0172

byte mode

function 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 3
end 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 Edit: 2015-02-16 06:39:01 by ficedula »

DLPB_

  • Banned
  • *
  • Posts: 11006
    • View Profile
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #3 on: 2015-02-16 01:46:57 »
Thanks for this!  It will definitely help!

nfitc1

  • *
  • Posts: 3011
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #4 on: 2015-02-16 01:55:06 »
Let me know if there's any script PrC doesn't like. Its AI script editor is undoubtedly the shoddiest piece of it.

paul

  • *
  • Posts: 179
    • View Profile
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #5 on: 2015-02-16 11:24:47 »
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

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #6 on: 2015-02-17 16:29:04 »
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).

Bosola

  • Fire hazard!
  • *
  • Posts: 1752
    • View Profile
    • My YouTube Channel
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #7 on: 2015-03-03 21:18:47 »
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 Edit: 2015-03-08 22:44:59 by Bosola »

Bosola

  • Fire hazard!
  • *
  • Posts: 1752
    • View Profile
    • My YouTube Channel
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #8 on: 2015-03-08 22:47:17 »
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]
#Some common battle values that you'll probably want
const word^ Enemies := $20A0
const word^ ActiveEnemies := $20B0
const word^ Targets := $2070
const word^ Allies := $2080
const word^ ActiveAllies := $2090
const word^ Me := $2060
const word^ AllCreatures := $2050

const word^ StatCurrentMP := $4140
const word^ StatMaxMP := $4150
const dword^ StatCurrentHP := $4160
const dword^ StatMaxHP := $4180


#Kinds of attack
const byte ENEMY_ATTACK := $20

raw function PickRandomBit(word w): dword
$82
end function

raw function Random: Word
$81
end function

raw function Perform(byte kind, word ability): void #Note attack kind FIRST, not ability code!
$92
end function

raw function LoadStats(word chars, dword stat): dword
$80
end function

raw function FindLargest(dword stats): dword
$84
end function

raw function FindSmallest(dword stats): dword
$85
end 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 Edit: 2015-03-08 22:53:03 by Bosola »

Kefka

  • *
  • Posts: 202
    • View Profile
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #9 on: 2015-03-09 14:27:11 »
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!

gjoerulv

  • *
  • Posts: 1225
  • me
    • View Profile
    • My Youtube
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #10 on: 2015-03-10 11:53:33 »
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

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
Re: [FF7] AI Script compiler - Conformer (v0.1)
« Reply #11 on: 2015-06-15 22:13:27 »
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;



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.