Symphonic Rain:Technical Documentation

From TLWiki
Jump to: navigation, search


File Format: .kgo script[edit]

Revision: 1.0 RC2 (2007-10-09)
Credits: Rasqual Twilight

Note: This documentation may be out of sync with the actual interpretation. Use at your own risk.

===================================      KOGADO Kuroneko Team - .kgo script file format / Scene.tbl
== KOGADO KGO SCRIPT FILE FORMAT ==      Documented by RasqualTwilight
===================================      Revision: v.1.0-RC2  2007-10-09





= Introduction =

This document describes the files used in the adventure mode of games created by Kogado's Kuroneko-san Team.
Although efforts have been made to keep it accurate for the various covered
games, no warranty is made as for the exactitude of the present document.




= Document technical conventions =

#######################################################################
The structure definitions in this document use datatypes found in Win32 programming.
* Byte order is Little-endian unless specified otherwise
(datatypes beginning with BE are Big-Endian byte-ordered)
For instance,
   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
  00 00 00 00 00 00 00 00 82 E6 82 EB 82 B5 82 A2
the value at offset 8 is 0xEB82E682 in LE order.

* a BYTE is an unsigned 8-bit variable (uint8)
  a CHAR is an 8-bit variable (char) which represents a character, comprised between 0 and 255.
** A C-style string ("NUL-terminated string") is a 
   sequence of characters whose value is not 0, followed by a 00 byte.

* a WORD is an unsigned 16-bit variable (uint16). Ranges [0-65535] included.
* a DWORD is an unsigned 32-bit variable (uint32). Ranges [0-2^32-1] included.
          It may also be used to represent a 32-bit memory address.
* [] indicate an array. Subscript indices start at 0. Array sizes are in decimal.
  a CHAR[] may also be the notation for a C-style string type.
  In particular cases, if the width is fixed, there may be no need to terminate the string with a NUL byte.
  Anyway, the document will explicitly state which convention is used.

* numbers prefixed with a "0x" string are in hexadecimal base

See http://wiki.xentax.com/index.php/DGTEFF if you are unfamiliar with these terms.
#######################################################################




= .kgo File Format =

The .kgo files are so-called scripts, prepared in a special formatting that
define a succession of actions affecting the game as presented to the user,
such as displaying a message, playing an animation made of successive bitmaps,
branch based on choices, etc.

** Each script may contain zero, one or more scenes
** Each script defines at least one function. Functions are entrypoints.
** While each scene is associated to a function,
   not all functions are accessed through a scene identifier.
   In other words, a script may EXPORT a function solely for use in other scripts.
   For instance, in Symphonic Rain, kgo0182.kgo defines no scene but exports SCR0182::Func_PassWord.
** Several scene identifiers may point to a single function.
   It means there can be more scenes than functions in a script.

It is up to the game engine to select which scene will be selected
when starting in scenario mode.
For example, Symphonic Rain defines two start routes at the main screen:
the Al Fine and Da Capo modes.

However, in "Dear Pianissimo Refrain" (and maybe later versions),
the Scene-Function association is missing. It can be assumed that
they are linked in the order they appear respectively, although this
does not prevent having more functions than scenes.



The general structure of a .kgo script is:
* Kgo Header:
** Fixed Header
** Variable Header (Scene Descriptors)
* Functions Data
* Special Strings ("Dear Pianissimo Refrain" and higher)
* Message Table



== Header ==

The beginning of the file is made of a header which always has a fixed part
and may also contain a variable part.

As you may suppose, the game engine has undergone various improvements
over time. The latest version available at the time of this writing
is featured in "Dear Pianissimo" and "Dear Pianissimo Refrain" (Fortell 2.00),
hereafter referred to as "DP".

Games using the Fortell engine are
* AC    Angelic Concert (2001-01-19)
* AS    Angelic Serenade (2002-03-29)
* ASDVD Angelic Serenade umaretabakari no Love Song (2003-03-19) - with plug-ins
* SR    Symphonic=Rain (2004-03-26)
* ACE   Angelic Concert Encore (2004-12-03)
* SRTE  Symphonic=Rain Treasure Edition (aisouban) (2005-06-24)
* ASN   Angelic Serenade Rabbie aisouban (2005-12-22)
* DP    Dear Pianissimo (2006-08-11)
* DPR   Dear Pianissimo Refrain (2007-06-29)

The only engines being considered in this document are SR, SRTE, ACE (roughly the same)
and DP.


== Fixed Header ==

The size of the fixed part is as following:
* SR/SRTE/ACE: header 0x34 (52) bytes
* DP:          header 0x40 (64) bytes

Here is a possible interpretation of the fixed header:

struct KgoScriptHeader  // 0x34 or 0x40 bytes
{
	[00] CHAR[4]   GameTag;             // e.g. "SR01" "AE01" "DP01" "DP20" actually unchecked by the program
	[04] DWORD     ScriptFilesize;      // size of current script
	                                    // useful, because .kgo scripts are usually contained
	                                    // in a HyPack-compressed archive, e.g. script.pak)
	[08] DWORD     ScriptNumber;        // current script's number
	[0C] DWORD     ?CRC?;               // unknown

	                                    //» #ignored. Maybe used in earlier versions.
	[10] DWORD     KgoFixedHeaderSizeIgnored;
	[14] DWORD     KgoVariableHeaderSizeIgnored;
	[18] DWORD     SceneDescriptorsCountIgnored;
	                                    //»

	[1C] DWORD     KgoHeaderSize;       // The .kgo header contains a fixed part plus an optional variable part
	                                     // #SR01, AE01: includes fixed part 0x34 (52) bytes
	                                     // #DP01,DP20: includes fixed part 0x40 (64) bytes
	                                     // if (KgoHeaderSize > fixed part size)
	                                     // @offset 0x34/0x40: array KgoSceneDescriptor[SceneDescriptorsCountIgnored]
	                                    // Note: also possible to rely on [10-1B] info to determine this size,
	                                    // however [10]+[14] is not necessarily aligned on a boundary thus may be != KgoHeaderSize

	[20] DWORD     KgoFunctionDataSize; // See "Format of Kgo Function Data" section below for details on this area

	                                    //» #ignored. Maybe used in earlier versions.
	[24] DWORD     KgoFunctionCountIgnored;
	                                    //»

	                                    //» #DP01: ignored. Use [34-3F] instead
	                                    //  #DP20: used for non-dialogue text, such as scene names, maybe function calls (:: notation).
	                                    //  Note that scripts that return to main menu generally have [2C] set to zero.
	                                    //  The format of the region is documented below.
	[28] DWORD     TextOffset;          // set if TextLength is not zero. Normally equals (HeaderSize + KgoFunctionDataSize)
	[2C] DWORD     TextLength;          // May be zero. @offset: (TextOffset + TextLength) may be before EOF because of memory Alignment
	[30] DWORD     MessageEntriesCount; // Number of strings in message table
	                                    //»

//	#SR01,AE01: fixed header ends here

	                                    //» #DP01,DP20: specific fields start here.
	[34] DWORD     TextSectionOffset;   // Offset of Text Section
	[38] DWORD     TextSectionSize;     // Section ends at last WORD-aligned '00' byte
	[3C] DWORD     MessageEntriesCount2;// Number of strings in ext message table
	                                    //»
};


== Variable Header (Scene Descriptors) ==

A single script may contain zero, one or several scenes.
This comes right after the fixed header, but can also be absent if the script defines no scene.
* Starts at file offset 0x34 or 0x40 depending on engine version.
* Check KgoScriptHeader::KgoHeaderSize and/or KgoScriptHeader::KgoVariableHeaderSizeIgnored
  to know whether it is valid to read at this offset.

* If there are several functions in a script, the layout is:
FIXHEAD
VARHEAD << described here
DATA1
DATA2 etc. (one for each Func, not scene)
MSG

struct KgoSceneDescriptor  // variable size
{
	[00] WORD      SizeOfSceneDescriptor;
	                                    //» #SR01,AE01: 0x20 (32) (offsetof(descriptor_i) == 0x34 + i * 0x20)
	                                    //  #DP01,DP20: variable (because of memory alignment)

	                                    //» #SR01,AE01: Aligned block size necessary for scene name.
	[02] WORD      SceneNameAllocSize;
	                                    //» #DP01,DP20
	[02] WORD      ScriptNumber;
	                                    //»

	                                    //» #SR01,AE01: Script containing the scene
	[04] WORD      ScriptNumber;
	                                    //» #DP01,DP20: Always 0, ignored
	[04] WORD      ZeroFieldIgnored;
	                                    //»

	                                    //» #SR01,AE01
	[06] WORD      ?SomeSize?;
	                                    //» #DP01,DP20
	[06] WORD      SceneNameAllocSize;
	                                    //»

	                                    //» #DP20
	[08] DWORD     Ignored;             // Offset is always function's (0x0A + KgoData::SceneFuncnameAllocSize)
	                                    //» #others
	[08] DWORD     OffsetInData;        // Offset in the KgoData section of .kgo (bytecode offset)
	                                    //»

	                                    //» #DP20
	[0C] WORD      ?ZeroFieldIgnored?;
	                                    //»

	[0C+x] DWORD   SceneID;             // ID defined in script header (a script may contain several scenes)
	[10+x] DWORD   SceneID2;            //  ditto
	[14+x] CHAR    SceneName[SceneNameAllocSize];
	                                    // NUL-terminated scene name.
	                                    // #DP01,DP20: Zero-padded to closest upper WORD boundary.
};

The scene ID's are used in the scene hashtable
(see section "Scene.tbl file format (HashTable)" for details)
The name of the first scene to be loaded in story mode is game-dependant.
In SRTE, it is either a01 (Al Fine) or t01 (Da Capo).



== Format of Kgo Function Data (KgoFunctionDataSize bytes) ==

Starts at file offset KgoScriptHeader::KgoHeaderSize and has
size KgoScriptHeader::KgoFunctionDataSize.
Repeated KgoScriptHeader::KgoFunctionCountIgnored times.


struct KgoData  // variable size
{
	                                    //» #SR01,AE01
	[00] DWORD     SizeOfFuncData;      // (=KgoFunctionDataSize if only one Func)
	                                    //» #DP01,DP20
	[00] WORD      SizeOfFuncData;
	[02] WORD      ZeroFieldIgnored;
	                                    //»

	[04] WORD      SceneFuncnameAllocSize;

	                                    //» #SR01,AE01
	[06] WORD      ZeroFieldIgnored;    // Let extra = 2
	                                    //»
	[06+extra] DWORD                         SceneDataSectionSize; // Section ends at last WORD-aligned '00' byte
	[0A+extra] CHAR[SceneFuncnameAllocSize]  SceneFuncname[SceneFuncnameAllocSize]; // NUL-terminated and Zero-padded Function name
	[yy]       CHAR[Remainder]               SceneDataSectionBlob; // yy = 0A+extra+SceneFuncnameAllocSize; Remainder = SizeOfFuncData - yy;
};
[zz]       CHAR[tt] PADDING;            // Pads to next WORD boundary


=== Format of KgoData::SceneDataSectionBlob ===

The data block is made of a simple assembly-like language that could be disassembled into mnemonics
(human-readable virtual machine operations).
Each mnemonic is associated to a WORD value between 0 and a version-specific limit representing the command.
This language also defines an argument stack for passing values to called services.

For instance:
The 0x0 (00 00) command is NOP (No-Operation)
    0x1 (01 00) command is PUSH: loads a DWORD onto the stack, that is to say is followed by a DWORD value.
    0x72 (72 00) is AVGPAUSE and takes zero argument.

There are two types of mnemonics:
* Mnemonics that are "read-ahead", that is to say require to read more than just the WORD value.
  They are a minority (in parenthesis, meaning of read-ahead value):
  PUSH (DWORD:value), JMP (DWORD:offset), JF (DWORD:offset), JT (DWORD:offset), JMPPLUS (int32:offset)
**  Here's an example stream pushing a value: 01 00 C0 03 00 00  = PUSH(3c0)
**  Here's a JMP that serves no purpose: 05 00 06 00 00 00 = JMP(+6)
* Mnemonics that require zero, one or more arguments obtained from the argument stack
** For instance, 0x4B plays a voice file. 
  01 00 EB 03 00 00  = PUSH(3eb)
  4B 00              = PlayVoice(Arg1)
   and the DWORD 3eb is removed ("popped") from the stack.

The argument stack is augmented by instructions such as PUSH of course, but some called functions also
modify the stack after they are called. For instance, PUSHCMPGT takes 2 arguments (removes them) and
pushes a value on the stack depending of the result of the comparison. Another example is
AVGPLACESELECT, which takes no argument and repushes a value on the stack.

Arguments are pushed Left-To-Right when calling a function.
It can be seen with the AVGCHOICE mnemonic which takes 4 arguments (string references), but ignores
string references set to zero. For example, the used VM instructions coumd be:
    PUSH "Choice #1"   # Actually pushing a DWORD value, the assembler takes care of the string-to-integer translation
    PUSH "Choice #2"
    PUSH 0
    PUSH 0
    AVGCHOICE

And choice options are presented in this order on the game screen.



== Format of TextSection ==

The Text Section contains all strings used in the script. It can be:
* Scene identifiers ("bt03")
* Function identifiers ("SCR0183::Func_GrandEnd")
* Game scenario dialogue line
* Choice label

This section is simply an aggregation of String Blocks, with the following information

struct KgoStringBlock  // variable size
{
	[00] WORD                       StringBlockSize;  // rounded to upper WORD boundary
	[02] CHAR[StringBlockSize - 2]  StringEntry;      // Text, or scene name, NUL-terminated and zero-padded.
};

Those blocks are indexed by their order of appearance and may be displayed in the
scene using the appropriate functions.
Indexing starts at 1 (i.e. PUSH 1  refers to the first string block of the text section).

=== Format of Text [24] ("Special Strings") for DP20 ===

* Scene identifiers ("inter01")
* Function identifiers maybe ("SCR0183::Func_GrandEnd")

struct KgoSpecialStringBlock  // variable size
{
	[00] WORD                       SpecialStringBlockSize;  // not rounded
	[00] WORD                       Unknown;  // always 3? - is not (SpecialStringBlockSize / 4)
	[02] CHAR[StringBlockSize - 4]  SpecialStringEntry;      // Text, or scene name, NUL-terminated.
};

Indexing starts at 0.




= Scene.tbl file format (HashTable) =

This file references the game scenes, with information such as which
script file contains a given scene.

== Flat Organization ==

struct SceneTable  // 0x8 or 0xC + variable size
{
	                                    //» #DP20
	[00] CHAR[4]   GameTag;             // e.g. "DP20"
	                                    //»

	[00+x] DWORD     HashTableFilesize    // Bytes
	[04+x] DWORD     HashTableCount;      // Number of scene buckets
}


struct SceneBucket
{
	[00] WORD      SizeOfSceneBucket;

	                                    //» #SR01,AE01: scene name string length
	[02] WORD      ScenenameAllocSize;
	                                    //» #DP01,DP20: Script containing the scene
	[02] WORD      ScriptNumber;
	                                    //»

	                                    //» #SR01,AE01
	[04] WORD      ScriptNumber;
	                                    //» #DP01,DP20: Script containing the scene
	[04] WORD      ZeroIgnored;
	                                    //»

	                                    //» #SR01,AE01: ?Some Size?
	[06] WORD      ??;
	                                    //» #DP01,DP20
	[06] WORD      ScenenameAllocSize;
	                                    //»

	                                    //» #DP20
	[08] DWORD     Ignored;             // Offset is always function's (0x0A + KgoData::SceneFuncnameAllocSize)
	                                    //» #others
	[08] DWORD     OffsetInData;
	                                    //»

	                                    //» #DP20
	[0C] WORD      ??;
	                                    //»

	[0C+x] DWORD     SceneID;           // ID defined in .kgo script header (a script may contain several scenes)
	[10+x] DWORD     SceneID2;          //  ditto
	[14+x] CHAR[xx]  SceneName;         // NUL-terminated scene name
	                                    // #SR01,AE01: SizeOfSceneBucket = 0x20 (32) bytes
	                                    // #DP01,DP20: SizeOfSceneBucket = variable
};


= Random Notes =

Let: g_offset = 16;

00424804     /$  55                   PUSH    EBP
00424805     |.  8BEC                 MOV     EBP, ESP
00424807     |.  BA 02000000          MOV     EDX, 2
0042480C     |.  8B45 08              MOV     EAX, [ARG.1]                        ;  memory address of KgoData + offset
0042480F     |.  66:8B00              MOV     AX, WORD PTR [EAX]
00424812     |.  66:83F8 10           CMP     AX, 10
00424816     |.  73 15                JNB     SHORT SR_fixed.0042482D
00424818     |.  66:FFC8              DEC     AX
0042481B     |.  74 0B                JE      SHORT SR_fixed.00424828
0042481D     |.  83C0 FE              ADD     EAX, -2
00424820     |.  66:83E8 04           SUB     AX, 4
00424824     |.  72 02                JB      SHORT SR_fixed.00424828
00424826     |.  EB 05                JMP     SHORT SR_fixed.0042482D
00424828     |>  BA 06000000          MOV     EDX, 6
0042482D     |>  8BC2                 MOV     EAX, EDX
0042482F     |.  5D                   POP     EBP
00424830     \.  C3                   RETN

Load 3funcs(Cmd) = {
ESI = *(unsigned WORD*)(&Cmd)  (Zero extend Cmd)
EDX = 3 * ESI
fn1 = (DWORD*)0x596090 + 4 *EDX
fn2 = (DWORD*)0x596094 + 4 *EDX
fn3 = (DWORD*)0x596098 + 4 *EDX
}
fn1 must be non-null (SRTE: roughly Cmd in [0-152] with some holes)



- SRTE/DP FadeMasks:
4 "FadeMask02_LucasR.bmp"
5 "FadeMask03_LucasL.bmp"
6 "FadeMask00_BlindR.bmp"
7 "FadeMask01_BlindL.bmp"
C Translate To Foreground effect
D Translate To Background effect
E Water effect
F Moving Light Source effect with "HaloBack.bmp"
10 "FadeMask04_Circle.bmp"
11 "FadeMask05_CircleR.bmp"
12 "FadeMask06_Clock.bmp"
13 "FadeMask07_Swirl.bmp"
14 "FadeMask08_Crystal.bmp"
15 "FadeMask09_StripesB.bmp"
16 "FadeMask10_StripesN.bmp"
17 "FadeMask11_Star.bmp"
18 "FadeMask12_Radiation.bmp"
19 "FadeMask13_RadiationR.bmp"
1A "FadeMask14_Windmill.bmp"
1B "FadeMask15_Naruto.bmp"
1C "FadeMask16_Noise.bmp"


File Format: .kgo script mnemonics[edit]

Revision: see wiki history
Credits: History

Note: This documentation may be out of sync with the actual interpretation. Use at your own risk.

# Args Mnemonic Description Repush
0 (0000h) 0 NOP Do Nothing 0
1 (0001h) 0 PUSH Push a signed 4-byte integer on arg stack (read ahead) 0
2 (0002h) 1 POP Pop stacked(Arg1:Returned Value) 0
3 (0003h) 0 JMP Jump, set offset = offset + read-ahead-DWORD [offset points at 03 bytecode] (read ahead) 0
4 (0004h) 1 JF Jump if false(Arg1:bool), set offset = offset + read-ahead-DWORD [offset points at 04 bytecode] (read ahead) 0
5 (0005h) 1 JT Jump if true(Arg1:bool), set offset = offset + read-ahead-DWORD [offset points at 05 bytecode] (read ahead) 0
6 (0006h) 0 JMPPLUS Jump to another scene in same kgo, set offset = offset + read-ahead-DWORD (possibly negative) - Should land on scene start [offset points at 06 bytecode][SRTE:Unused] (read ahead)(Repush 1) 1
7 (0007h) 1 CALLFUNC CallFunction(Arg1:FuncIdStringIndex[0-0xFFFF]). Syntax of function identifier is SCRIPT::FuncName e.g. SCR0180::Func_b05_2 (Repush 1) 1
8 (0008h) 0 PUSHEVAL Push Last Play Evaluation (Repush 1) 1
9 (0009h) 2 PUSHSWAPTWO Swap two stacked arguments(Arg1, Arg2)[SRTE:Unused] (Repush 2) 2
10 (000Ah) 1 PUSHEVALTWO Push Last Play Evaluation, then push Arg1(Arg1)[SRTE:Unused] (Repush 2) 2
11 (000Bh) 3 PUSHSWAPTWOTHREE Swap two stacked arguments Arg2 and Arg3(Arg1, Arg2, Arg3) (Repush 3) 3
14 (000Eh) 1 ENDSCRIPT EndOfScript(Arg1=0). Provides fail-safe script termination. Pass Arg1 as 0 (NOP) due to instructions aligned on word boundaries. Should be the last instruction 0
15 (000Fh) 0 ENDSCRIPT2 EndOfScript2()[SRTE:Unused]. Provides fail-safe script termination. 0
16 (0010h) 1 PUSHNOT Replace stacked bool Arg1:bool by: repush (!Arg1) (Repush 1) 1
19 (0013h) 2 PUSHMUL Multiply (Arg1, Arg2), repush (Arg1 * Arg2) (Repush 1) 1
20 (0014h) 2 PUSHIDIVZ Integer Divide with SignedZeroCheck (Arg1, Arg2), repush (Arg2 ? Arg2 / Arg1 : Arg1 >= 0 ? 0 : -1) (Repush 1) 1
21 (0015h) 2 PUSHIDIV Integer Divide with ZeroCheck (Arg1, Arg2), repush (Arg2 ? Arg2 / Arg1 : 0) (Repush 1) 1
22 (0016h) 2 PUSHADD Add (Arg1, Arg2), repush (Arg1 + Arg2) (Repush 1) 1
23 (0017h) 2 PUSHSUB Substract (Arg1, Arg2), repush (Arg2 - Arg1) (Repush 1) 1
24 (0018h) 2 PUSHCMPGT Compare GreaterThan(Arg1,Arg2), repush (Arg1 > Arg2) (Repush 1) 1
25 (0019h) 2 PUSHCMPGE Compare GreaterOrEqual(Arg1,Arg2), repush (Arg1 >= Arg2) (Repush 1) 1
26 (001Ah) 2 PUSHCMPLT Compare LessThan(Arg1,Arg2), repush (Arg1 < Arg2) (Repush 1) 1
27 (001Bh) 2 PUSHCMPLE Compare LessOrEqual(Arg1,Arg2), repush (Arg1 <= Arg2) (Repush 1) 1
28 (001Ch) 2 PUSHCMPEQ Compare Equal(Arg1,Arg2), repush (Arg1 == Arg2) (Repush 1) 1
29 (001Dh) 2 PUSHCMPNE Compare NotEqual(Arg1,Arg2), repush (Arg1 != Arg2) (Repush 1) 1
30 (001Eh) 2 PUSHAND BooleanAnd(Arg1,Arg2), repush (Arg2 && Arg1) (Repush 1) 1
31 (001Fh) 2 PUSHOR BooleanOr(Arg1,Arg2), repush (Arg2 || Arg1) (Repush 1) 1
32 (0020h) 2 SETFLAGVAR_MAYBE Set FLAG Variable?(Arg1:bool,Arg2:[0-0x1FF]) 0
33 (0021h) 1 PUSHFLAGVAR_MAYBE Push FLAG Variable?(Arg1:[0-0x1FF], repush <bool>) (Repush 1) 1
34 (0022h) 2 SETFLAGALT_MAYBE Set Alt FLAG Variable?(Arg1:bool,Arg2:[0-0x3F]) 0
35 (0023h) 1 PUSHFLAGALT_MAYBE Push Alt FLAG Variable?(Arg1:[0-0x3F], repush <bool> FALSE if Arg1 off-range; X=(Arg1/8),Xin[0-7] Y=(Arg1%7) EDX=2^Y EAX=[005EEA40+X] 005EEA40:=00,00,00,00,00,00,20,83 EDX=EDXxorEAX repush (EDX!=0) (Repush 1) 1
36 (0024h) 2 SETVARALT_MAYBE Set Alt Variable?(Arg1,Arg2:[0-0x3F]) 0
37 (0025h) 1 INCVARALT_MAYBE Increment Alt Variable?(Arg1:[0-0x3F]) 0
38 (0026h) 1 DECVARALT_MAYBE Decrement Alt Variable?(Arg1:[0-0x3F]) 0
39 (0027h) 1 PUSHVARALT_MAYBE Push Alt Variable?(Arg1:[0-0x3F]) (Repush 1) 1
40 (0028h) 2 OPCODE40 Unresolved 40(Arg1, Arg2) 0
41 (0029h) 1 PUSHSIGNBIT Push Sign Bit(Arg1)[SRTE:Unused] (Repush 1) 1
42 (002Ah) 1 ASSIGNEVAL Assign Evaluation(Arg1:Evaluation[0-59]) 0
43 (002Bh) 0 PUSHASSIGNEDEVAL Push Assigned Evaluation (Repush 1) 1
48 (0030h) 1 AVGSCENE Set Scene(Arg1:SceneNameStringIndex[0-0xFFFF]) 0
64 (0040h) 1 AVGMSG MessageText(Arg1:StringIndex[0-0xFFFF]). If a text is already displayed, appends. 0
65 (0041h) 0 AVGCRLF Message Newline() 0
66 (0042h) 0 AVGCLR ClearMessagePanel() 0
67 (0043h) 0 AVGOPEN OpenMessagePanel() 0
68 (0044h) 0 AVGCLOSE CloseMessagePanel() 0
69 (0045h) 1 AVGFORCESPD ForceMessageSpeed(Arg1:[0-3000]) 0
70 (0046h) 1 AVGVNMODE SetVisualNovelMode(Arg1:bool) 0
71 (0047h) 2 AVGVNPOS SetVNModeTextPos(Arg1:TopBlankLinePadding[0-25], Arg2:LeftWhitespacePadding[0-15] 0
72 (0048h) 1 AVGPAUSE Pause Engine (Arg1:Time_ms) 0
73 (0049h) 0 AVGNEXT Prompt for user click() 0
74 (004Ah) 1 AVGFORCENOSKIP ForceUnskippableMessage(Arg1:bool) 0
75 (004Bh) 1 AVGVOICE PlayVoice(Arg1:Num "%06d.wav") ("Voice\srev%03d.pak") 0
76 (004Ch) 1 AVGVOLUME SetVolume(Arg1:[0-100]) 0
77 (004Dh) 2 AVGVOICEPOS SetVoicePosition(Arg1:Z, Arg2:X), Args are rounded to [-INF;-12]u[12;+INF] depending on sign. Args are expressed in hundreds of unit. 0
78 (004Eh) 2 UNK_78 Unresolved 78(Arg1:bool, Arg2:bool)[SRTE:Unused] 0
79 (004Fh) 1 UNK_79 Unresolved 79(Arg1:bool)[SRTE:Unused] 0
80 (0050h) 1 UNK_80 Unresolved 80(Arg1:[0-100]) 0
81 (0051h) 2 UNK_81 Unresolved 81(Arg1:bool, Arg2)[SRTE:Unused] 0
82 (0052h) 1 UNK_82 Unresolved 82(Arg1:bool)[SRTE:Unused] 0
83 (0053h) 1 UNK_83 Unresolved 83(Arg1:[0-100]), Same as UNK_80? 0
84 (0054h) 1 AVGSE PlaySpecialEffect(Arg1:Num "srse%03d.wav") 0
85 (0055h) 0 AVGSESTOP StopSpecialEffect() Stop currently playing non-looping SE, if applicable 0
86 (0056h) 1 AVGSEVOLUME SetSpecialEffectVolume(Arg1:[0-100]), Set volume for non-looping SE. 0
87 (0057h) 2 AVGSEPOS SetSpecialEffectPosition(Arg1:Z, Arg2:X) 0
88 (0058h) 2 UNK_88 Unresolved 88(Arg1:bool, Arg2)[SRTE:Unused] 0
89 (0059h) 1 UNK_89 Unresolved 89(Arg1:bool)[SRTE:Unused] 0
90 (005Ah) 1 OPCODE90 [Unreviewed](Arg1:[0-100]) 0
91 (005Bh) 2 OPCODE91 [Unreviewed](Arg1, Arg2) 0
92 (005Ch) 1 UNK_92 Unresolved 92(Arg1:BgAnimation) 0
93 (005Dh) 0 UNK_93 Unresolved 93() BgAnimation = 3E6 0
94 (005Eh) 0 UNK_94 Unresolved 94() BgAnimation = 3E7 0
95 (005Fh) 2 UNK_95 Unresolved 95(Arg1:[0-2], Arg2) 0
96 (0060h) 1 UNK_96 Unresolved 96(Arg1), like UNK_95 w/Arg2=-1 0
97 (0061h) 1 AVGFADE FadeAnimation(Arg1:FadeMask) 0
98 (0062h) 2 AVGBGFADE FadeBgAnimation(Arg1:FadeMask, Arg2:OptionalTargetBgCGNum indirectly used in "srbg%03d.bmp", see AVGBGFADEINTO) 0
99 (0063h) 1 AVGFADEWHITE FadeToWhite(Arg1:FadeMask) 0
100 (0064h) 1 AVGFADEBLACK FadeToBlack(Arg1:FadeMask) 0
101 (0065h) 3 AVGCHARONE ShowOneChar(Arg1:FadeMode[0-2], Arg2:CharSlot[0=Center,1=Left,2=Right], Arg3:CGNum) 0
102 (0066h) 2 UNK102 Unresolved 102(Arg1:[0-2], Arg2:[0-2]) 0
103 (0067h) 0 OPCODE103 [Unreviewed]() 0
104 (0068h) 0 UNK104 Unresolved 104() 0
105 (0069h) 1 OPCODE105 [Unreviewed](Arg1) 0
106 (006Ah) 0 OPCODE106 [Unreviewed]() 0
107 (006Bh) 0 OPCODE107 [Unreviewed]() 0
108 (006Ch) 1 AVGPLACE ShowPlaceLabel(Arg1:Num "AvgPlace%02d.png") 0
109 (006Dh) 1 OPCODE109 [Unreviewed](Arg1) 0
110 (006Eh) 0 OPCODE110 [Unreviewed]() (Repush 1) 1
111 (006Fh) 0 OPCODE111 [Unreviewed]() (Repush 1) 1
112 (0070h) 0 OPCODE112 [Unreviewed]() (Repush 1) 1
113 (0071h) 0 OPCODE113 [Unreviewed]() (Repush 1) 1
114 (0072h) 1 AVGBGFADEINTO SetFadeBgInto(Arg1=?), specifies that next AVGBGANIM instruction will fade into a new Bg 0
115 (0073h) 0 OPCODE115 [Unreviewed]() (Repush 1) 1
116 (0074h) 0 OPCODE116 [Unreviewed]() (Repush 1) 1
117 (0075h) 0 OPCODE117 [Unreviewed]() (Repush 1) 1
118 (0076h) 1 AVGBGEFFECT SetBackgroundEffect(Arg1:EffectMode[0=Sunset,1=Gray,2=Gray+Rain,3=Gray+Snow,4=Sunset+OldFilm,5=Gray]) 0
119 (0077h) 0 OPCODE119 [Unreviewed]() (Repush 1) 1
120 (0078h) 4 AVGCHOICE Prompt Choice and Push Selected Entry(Arg1=0orStringIndex, Arg2=0orStringIndex, Arg3=StringIndex, Arg4=StringIndex), Pushed Value is Arg4 => 0, Arg3 => 1 etc. 1
121 (0079h) 0 AVGNOTIFYLOADING NotifyLoading() 0
122 (007Ah) 1 OPCODE122 [Unreviewed](Arg1) 0
123 (007Bh) 0 OPCODE123 [Unreviewed]() 0
124 (007Ch) 1 AVGSONG Loads a song in play mode and Set Last Evaluation (Arg1:HUNDREDS=EventNum;Event#.pak;UNITS=SongNum;e.g.SR##) (Repush 1) 1
125 (007Dh) 0 OPCODE125 [Unreviewed]() 0
126 (007Eh) 0 OPCODE126 [Unreviewed]() 0
127 (007Fh) 2 OPCODE127 [Unreviewed](Arg1:bool, Arg2:[0-9]) 0
128 (0080h) 0 AVGPLACESELECT SelectPlace() (Repush 1) 1
129 (0081h) 1 OPCODE129 [Unreviewed](Arg1) 0
130 (0082h) 1 OPCODE130 [Unreviewed](Arg1) 0
131 (0083h) 1 OPCODE131 [Unreviewed](Arg1:[0-100]) 0
132 (0084h) 0 OPCODE132 [Unreviewed]() 0
133 (0085h) 0 OPCODE133 [Unreviewed]() 0
134 (0086h) 1 UNK134 Unresolved 134(Arg1:bool) 0
135 (0087h) 1 AVGMSGPANELVIS SetMessagePanelVisibility(Arg1:bool) 0
136 (0088h) 1 UNK136 Unresolved 136(Arg1:bool) 0
137 (0089h) 1 AVGMSGPANELTWOVIS SetMessagePanel2Visibility(Arg1:bool) 0
138 (008Ah) 1 AVGBGM SetBackgroundMusic(Arg1;Num "Track%02d.bgm") 0
139 (008Bh) 0 UNK139 Unresolved 139() 0
140 (008Ch) 1 UNK140 Unresolved 140(Arg1) 0
141 (008Dh) 0 OPCODE141 [Unreviewed]() 0
142 (008Eh) 1 AVGLOOPSE SetLoopingSpecialEffect(Arg1:Num "srse%03d.wav") 0
143 (008Fh) 0 UNK143 Unresolved 143() 0
144 (0090h) 1 UNK144 Unresolved 144(Arg1:[1-14]) 0
145 (0091h) 1 AVGMSGPANELX MessagePanel::SetSizeX(Arg1:Num[0-0x100]) 0
146 (0092h) 0 UNK146 Unresolved 146() (Repush 1) 1
147 (0093h) 1 OPCODE147 [Unreviewed](Arg1:[0-3]) 0
148 (0094h) 0 OPCODE148 [Unreviewed]() (Repush 1) 1
149 (0095h) 1 OPCODE149 [Unreviewed](Arg1) 0
150 (0096h) 1 OPCODE150 [Unreviewed](Arg1) 0
151 (0097h) 1 OPCODE151 [Unreviewed](Arg1) 0
152 (0098h) 1 OPCODE152 [Unreviewed](Arg1) 0
153 (0099h) 1 OPCODE153 [Unreviewed](Arg1)[SRTE:Unsupported] 0
154 (009Ah) 1 OPCODE154 [Unreviewed](Arg1)[SRTE:Unsupported] 0
155 (009Bh) 0 OPCODE155 [Unreviewed]()[SRTE:Unsupported] 0
156 (009Ch) 0 OPCODE156 [Unreviewed]()[SRTE:Unsupported] 0
157 (009Dh) 1 OPCODE157 [Unreviewed](Arg1)[SRTE:Unsupported] 0
158 (009Eh) 0 OPCODE158 [Unreviewed]()[SRTE:Unsupported] 0
159 (009Fh) 1 OPCODE159 [Unreviewed](Arg1)[SRTE:Unsupported](Arg1:[>0] 0
160 (00A0h) 1 OPCODE160 [Unreviewed](Arg1)[SRTE:Unsupported] 0
161 (00A1h) 1 OPCODE161 [Unreviewed](Arg1)[SRTE:Unsupported] 1
162 (00A2h) 1 OPCODE162 [Unreviewed](Arg1)[SRTE:Unsupported] 0
163 (00A3h) 1 OPCODE163 [Unreviewed](Arg1)[SRTE:Unsupported] 0
164 (00A4h) 0 OPCODE164 [Unreviewed]()[SRTE:Unsupported][ACE:Unsupported] 0