BF is a binary format compiled from scripts created by Atlus. Logic during gameplay in almost all Persona games and several other Atlus entries is completely handled by BF files. For example, enemy AI, setting and checking flags for displaying dialog, starting scripted battles etc.
BF files usually also contain and reference BMD files (Atlus's compiled message format).
TGE'S AtlusScriptToolchain can manage BF files.
AtlusScriptCompiler is a commandline program that is part of the AtlusScriptToolchain. By providing the following arguments, for example, you can decompile a BF binary to an editable .flow (flowscript). Any embedded BMD files also get decoded to .msg (messagescript) in the process. Both can be modified using a text editor like Notepad++.
AtlusScriptCompiler.exe input.bf -Decompile -Library P5 -Encoding P5
You can then recompile the .flow (and any other included .flow or .msg files referenced in the .flow) into a new BF file using commandline arguments:
AtlusScriptCompiler.exe input.bf.flow -Compile -OutFormat V3BE -Library P5 -Encoding P5
The compiler can be downloaded here as part of AtlusScriptToolchain, along with a GUI that allows you to drag and drop files to compile/decompile them automatically without needing to use commandline arguments.
The compiler is a perpetual work in progress and does not always recompile flowscripts with 100% accuracy. As a result, unexpected glitches may occur ingame. One workaround, if you're only interested in editing the script's text, is to use the BFMessageScriptEditor program. Simply drag a BF file onto the exe to extract a .msg (messagescript), edit it with your text editor of choice, and drag it onto the exe when you're done. This will replace the embedded BMD in the BF without recompiling the script itself.
Uses the common header structure used in other files.
|0x0||U8||File type. Always 0 for BF|
|0x1||U8||Compression flag. Very rarely used on archives.|
|0x2||U16||User ID. Always 0 but can be set to any value. Doesn't appear to be used.|
|0x8||U32||Magic identifier. Always "FLW0"|
|0xC||U32||Reserved. Stores the size in memory. This value is calculated during runtime.|
|0x10||U32||Number of entries of this type table. (Could be U16)|
Type Table Types
Describes a type of content in the BF file. In most BF files, there's 5 of these entries.
|3||Message script data|
Label or Procedure Entry
Labels and procedures are essentially the same with the only difference being their usage semantics.
|0x0||U8||Name of the label or procedure|
|0x28||U32||Entry point. Opcode index from which the procedure starts|
|0x2C||U32||Reserved. Not verified but it is most likely used to store a runtime value|
Procedures, or functions can take in arguments or return values. These however are processed at runtime.
Labels, or jump labels are equivalent to goto's in C-like languages. They directly jump to a location in the current procedure.
An instruction is made up out of an opcode and operand(s).
|0x0||U16||Opcodes. See opcodes below|
|0x2||U16||Reserved. Can be used as operand.|
The opcode tells the game's interpreter what to do, and the operands are the data the interpreter processes on.
|0||PUSHI||Push integer value onto the stack|
|1||PUSHF||Push float value onto the stack|
|2||PUSHIX||Push integer value onto the stack|
|3||PUSHIF||Push float value onto the stack|
|4||PUSHREG||Push result of a native function onto the stack|
|5||POPIX||Pop integer index from the stack|
|6||POPFX||Pop float index from the stack|
|8||COMM||Call a native function in the game by index|
|9||END||End branch. Used to return from procedures and exit statements such as if, loop, etc. Comparable to 'return' and 'break' in C|
|10||JUMP||Jump to a procedure by index. Comparable to 'goto' in C languages. Does not store the return address.|
|11||CALL||Call into a procedure by index. Pushes the return address to the stack.|
|13||GOTO||Jump to a label by index. Comparable to 'goto' in C languages|
|14||ADD||Pop 2 values off the stack, calculate the sum and push the result onto the stack|
|15||SUB||Pop 2 values off the stack, subtract the left hand value from the right hand value and push the result onto the stacK|
|16||MUL||Pop 2 values off the stack, multiply them and push the result onto the stack|
|17||DIV||Pop 2 values off the stack, divide the left hand value with the right hand value and push the result onto the stack|
|18||MINUS||Pop a values off the stack, negates it and pushes the result onto the stack|
|19||NOT||Pop a value off the stack, bitwise NOT the value and push the result onto the stack|
|20||OR||Pop 2 values off the stack, bitwise OR the left hand value with the right hand value and push the result onto the stack|
|21||AND||Pop 2 values off the stack, bitwise AND the left hand value with the right hand value and push the result onto the stack|
|22||EQ||Pop 2 values off the stack, push 1 if the left hand value is equal to the right hand value, if not, push 0 to the stack|
|23||NEQ||Pop 2 values off the stack, push 1 if the left hand value is not equal to the right hand value, if not, push 0 to the stack|
|24||S||Pop 2 values off the stack, push 1 if the left hand value is less than the right hand value, if not, push 0 to the stack|
|25||L||Pop 2 values off the stack, push 1 if the left hand value is greater than the right hand value, if not, push 0 to the stack|
|26||SE||Pop 2 values off the stack, push 1 if the left hand value is less than or equal to the right hand value, if not, push 0 to the stack|
|27||LE||Pop 2 values off the stack, push 1 if the left hand value is greater than or equal to the right hand value, if not, push 0 to the stack|
|28||IF||Pop a value off the stack and check if it isn't zero. If it is zero then jump to the specified label by index|
|29||PUSHIS||Push short integer value onto the stack|
|30||PUSHLIX||Push the value of the specified integer index onto the stack|
|31||PUSHLFX||Push the value of the specified float index onto the stack|
|32||POPLIX||Pop an integer value off the stack and store it in the specified integer index|
|33||POPLFX||Pop a float value off the stack and store it in the specified float index|
|34||PUSHSTR||Push the start index of a null terminated string in the string table to the stack|
Depending on the opcode either no operands are used, the reserved field is used as an operand or the next 4 bytes are used.