/*	
 *	bltml.h
 *
 *	BulletML
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2006-2017 Naoyuki Sawa
 *
 *	* Mon Dec 04 18:17:17 JST 2006 Naoyuki Sawa
 *	- 1st リリース。
 *	  コメントが未整備なので、このあと書く予定です。
 *	* Sun Dec 10 13:32:01 JST 2006 Naoyuki Sawa
 *	- クラス階層を変更し、単純化しました。
 *	  <変更前>
 *		BulletMLBase
 *		├BulletMLNode
 *		├BulletMLBullet
 *		├BulletMLAction
 *		└BulletMLValue
 *		　├BulletMLNumber
 *		　├BulletMLVar
 *		　├BulletMLUnExpr
 *		　└BulletMLBinExpr
 *	  <変更後>
 *		BulletMLNode
 *		BulletMLBullet
 *		BulletMLAction
 *		BulletMLValue
 *		├BulletMLNumber
 *		├BulletMLVar
 *		├BulletMLUnExpr
 *		└BulletMLBinExpr
 *	  このように変更した理由は、以下の通りです。
 *	  ・BulletMLBaseクラスには仮想デストラクタしか定義しておらず、また、派生クラスオブジェクトをBulletMLBaseとして共通に扱う場面も無く、無駄であった。
 *	  ・BulletMLBulletとBulletMLActionは実行時に頻繁に生成、破棄を繰り返すクラスであり、少しでもメモリ効率、速度効率を向上したい。
 *	  　上述の変更により、BulletMLBulletとBulletMLActionは仮想関数を持たないクラスとなり、各インスタンスにvptrが不要となり、メモリ節約できる。
 *	  　また、BulletMLBulletとBulletMLActionのコンストラクタ、デストラクタから、何も行わないBulletMLBaseのコンストラクタ、デストラクタを呼び出す手間が省ける。
 *	* Thu Dec 14 01:43:04 JST 2006 Naoyuki Sawa
 *	- コメントを追記しました。
 *	  BulletMLUserFuncの各コールバック関数仕様についてのコメントがまだなので、このあと書く予定です。
 *	  基本的には、libBulletMLのコールバック関数とほぼ同じ仕様です。
 *	  ただし、(libBulletMLにおける)SimpleBulletの概念は無く、すべて(libBulletMLにおける)ActiveBullet相当となります。
 *	* Mon Feb 26 16:37:00 JST 2007 Naoyuki Sawa
 *	- _BulletMLValue_vtbl,_BulletMLNumber_vtbl,_BulletMLVar_vtbl,_BulletMLUnExpr_vtbl,_BulletMLBinExpr_vtblをstatic→グローバルに変更しました。
 *	  実行時にXMLからツリーをロードするのでなく、C言語ソースで定義し、ロード時間を節約するためです。
 *	  アプリケーションプログラムのC言語ソース内で構造体を定義するために、各VTBLを参照できる必要があるため、上述のような変更を行いました。
 *	  詳しくは、「tool/bmlcnv」を参照してください。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'～'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Sat Jul 22 22:21:25 JST 2017 Naoyuki Sawa
 *	- bltml.h,bltml.cをWin32プロジェクトに含めました。
 */
#ifndef __BLTML_H__
#define __BLTML_H__

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

/****************************************************************************
 *	覚え書き
 ****************************************************************************/
#if 0
/*--------------------------------------------------------------------------*/

アプリケーションが知る必要のある構造体は、BulletMLNode、BulletMLBullet、BulletMLUserFuncだけです。
その他の構造体は全て内部使用であり、アプリケーションが直接利用することはありません。

/*--------------------------------------------------------------------------*/

<bulletml>のtype=vertical/horizontalは、BulletML自体の処理には一切影響を与えません。
必要に応じて、アプリケーションがBulletMLNode_getType()を呼び出してvertical/horizontalを取得し、利用してください。(通常は不要です)

BulletMLが規定していることは、一周を360で表すことのみで、どの方向が0であるかや、<accel>のhorizontal/verticalがどの角度に相当するかなどは、一切関知しません。
アプリケーションがどのように見なすか、だけです。

/*--------------------------------------------------------------------------*/

<bullet>直下の複数の<action>は、全て同時に起動し並行動作します。
<action>直下の複数の<action>は、その他のノードと同様に、逐次動作します。
以上は、オリジナルのBulletMLの挙動から推測したものですが、たぶん正式な仕様だと思います。

例1:
	<bullet>
		<action>
			①
		</action>
		<action>
			②
		</action>
	</bullet>

	①と②のactionは同時に起動してBulletMLActionが生成され、並行動作する。

例2-1:
	<action>
		<action>
			①
		</action>
		<action>
			②
		</action>
	</action>

	①が起動～完了～消滅してから、②が起動～完了～消滅する。

例2-2:
	<action>
		<changeSpeed>
			①
		</changeSpeed>
		<action>
			②
		</action>
		<action>
			<action>
				③
			</action>
			<action>
				④
			</action>
		</action>
		<changeSpeed>
			⑤
		</changeSpeed>
	</action>

	①が起動～完了～消滅、②が起動～完了～消滅。
	その後、③と④が同時に起動。両方が完了～消滅するのを待つ。一方が先に完了～消滅しても、もう一方の完了～消滅を待つ。
	その後、⑤が起動～完了～消滅する。

/*--------------------------------------------------------------------------*/

createBullet()コールバックの中で、ACTの実体にdirection,speedを格納した後にBulletMLBullet_new()を呼び出すと、<bullet>のdirectionやspeedが優先されます。(方法①)

例: 方法①

	void myCreateBullet(void* userData, fixed direction, fixed speed, BulletMLNode* bulletNode, const fixed params[/*BULLETML_MAX_PARAMS*/]) {
		ACTP* actp;
		actp = createBulletAct();
		actp->direction = direction;	/* これは<fire>による指定(またはデフォルト値)です */
		actp->speed = speed;		/* これは<fire>による指定(またはデフォルト値)です */
		actp->bullet = BulletMLBullet_new(bulletUserFunc, actp, bulletNode, param);	/* <bullet>にdirectionやspeedの指定があれば、この中でコールバックされます */
	}

createBullet()コールバックの中で、BulletMLBullet_new()を呼び出した後にACTの実体にdirection,speedを格納すると、<fire>のdirectionやspeedが優先されます。(方法②)

例: 方法②

	void myCreateBullet(void* userData, fixed direction, fixed speed, BulletMLNode* bulletNode, const fixed params[/*BULLETML_MAX_PARAMS*/]) {
		ACTP* actp;
		actp = createBulletAct();
		actp->bullet = BulletMLBullet_new(bulletUserFunc, actp, bulletNode, param);	/* <bullet>にdirectionやspeedの指定があれば、この中でコールバックされます */
		actp->direction = direction;	/* これは<fire>による指定(またはデフォルト値)です */
		actp->speed = speed;		/* これは<fire>による指定(またはデフォルト値)です */
	}


なぜなら、createBullet()コールバックに渡されるdirectionとspeedは<fire>によるものであり、
もし<bullet>にdirectionやspeedが指定されていたら、BulletMLBullet_new()内から(必要に応じて)直ちにコールバックされるからです。
BulletMLBullet_new()の呼び出しよりも前に<fire>のdirectionとspeedを格納しておけば、コールバックによって上書きされ、<bullet>の設定が有効となります。
逆に、BulletMLBullet_new()の呼び出しよりも後で<fire>のdirectionとspeedを格納すれば、BulletMLBullet_new()内からの(必要に応じての)コールバックによって格納した<bullet>の設定は上書きされ、
<fire>の設定が有効となるわけです。

例:
	<action>
		<fire>
			<speed>
			<direction>10</direction>		…createBullet()コールバック引数に影響
			<speed>20</speed>			…createBullet()コールバック引数に影響
			<bullet>
				<direction>30</direction>	…BulletMLBullet_new()内からsetDirection()コールバック
				<speed>40</speed>		…BulletMLBullet_new()内からsetSpeed()コールバック
			</bullet>
		</fire>
	</action>

オリジナルのBulletMLの挙動では、<fire>と<bullet>両方にdirectionやspeedが指定されている場合、外側の<fire>の指定が有効となるようです。
すなわち、アプリケーション定義のcreateBullet()コールバック関数を方法②のように実装すれば、オリジナルのBulletMLと同じ挙動になります。

上述の仕様が正式仕様なのか、あるいは実装依存なのか、不明です。
アプリケーション毎に明確になっていれば、どちらの方法を選択しても良いと思います。

/*--------------------------------------------------------------------------*/

createBullet()コールバックの中で、渡されたBulletMLNodeに対してBulletMLNode_getLabel()を呼び出し、弾の種類を判別することができます。
これにより、ひとつのcreateBullet()コールバックで複数種類の弾の実体生成に対応することができます。
(このような処理は、必須ではありません。通常は、不要です。)

例:
	void myCreateBullet(void* userData, fixed direction, fixed speed, BulletMLNode* bulletNode, const fixed params[/*BULLETML_MAX_PARAMS*/]) {
		const char* label = BulletMLNode_getLabel(bulletNode);
		ACT* actp;
		if(!strcmp(label, "missile")) {
			actp = createMissileAct();	/* ミサイルを表すACTを作成 */
			actp->bullet = BulletMLBullet_new(missileUserFunc, actp, bulletNode, param);
		} else if(!strcmp(label, "laser")) {
			actp = createLaserAct();	/* レーザーを表すACTを作成 */
			actp->bullet = BulletMLBullet_new(laserUserFunc, actp, bulletNode, param);
		} else {
			actp = createBulletAct();	/* 通常の弾を表すACTを作成 */
			actp->bullet = BulletMLBullet_new(bulletUserFunc, actp, bulletNode, param);
		}
	}

/*--------------------------------------------------------------------------*/
#endif
/****************************************************************************
 *	
 ****************************************************************************/

typedef struct _BulletMLNode BulletMLNode;
typedef struct _BulletMLBullet BulletMLBullet;
typedef struct _BulletMLAction BulletMLAction;
typedef struct _BulletMLValue BulletMLValue;
/*├*/typedef struct _BulletMLNumber BulletMLNumber;
/*├*/typedef struct _BulletMLVar BulletMLVar;
/*├*/typedef struct _BulletMLUnExpr BulletMLUnExpr;
/*└*/typedef struct _BulletMLBinExpr BulletMLBinExpr;

typedef struct _BulletMLValue_vtbl BulletMLValue_vtbl;
/*├*/typedef struct _BulletMLNumber_vtbl BulletMLNumber_vtbl;
/*├*/typedef struct _BulletMLVar_vtbl BulletMLVar_vtbl;
/*├*/typedef struct _BulletMLUnExpr_vtbl BulletMLUnExpr_vtbl;
/*└*/typedef struct _BulletMLBinExpr_vtbl BulletMLBinExpr_vtbl;

extern const BulletMLValue_vtbl _BulletMLValue_vtbl;
extern const BulletMLNumber_vtbl _BulletMLNumber_vtbl;
extern const BulletMLVar_vtbl _BulletMLVar_vtbl;
extern const BulletMLUnExpr_vtbl _BulletMLUnExpr_vtbl;
extern const BulletMLBinExpr_vtbl _BulletMLBinExpr_vtbl;

static inline BulletMLValue* BulletMLNumber_super (BulletMLNumber * This) { return (BulletMLValue*)This; }
static inline BulletMLValue* BulletMLVar_super    (BulletMLVar    * This) { return (BulletMLValue*)This; }
static inline BulletMLValue* BulletMLUnExpr_super (BulletMLUnExpr * This) { return (BulletMLValue*)This; }
static inline BulletMLValue* BulletMLBinExpr_super(BulletMLBinExpr* This) { return (BulletMLValue*)This; }

/* BulletMLNode.name */
enum {
	BULLETMLNODE_NAME_BULLETML,
	BULLETMLNODE_NAME_BULLET,
	BULLETMLNODE_NAME_ACTION,
	BULLETMLNODE_NAME_FIRE,
	BULLETMLNODE_NAME_CHANGEDIRECTION,
	BULLETMLNODE_NAME_CHANGESPEED,
	BULLETMLNODE_NAME_ACCEL,
	BULLETMLNODE_NAME_WAIT,
	BULLETMLNODE_NAME_VANISH,
	BULLETMLNODE_NAME_REPEAT,
	BULLETMLNODE_NAME_DIRECTION,
	BULLETMLNODE_NAME_SPEED,
	BULLETMLNODE_NAME_HORIZONTAL,
	BULLETMLNODE_NAME_VERTICAL,
	BULLETMLNODE_NAME_TERM,
	BULLETMLNODE_NAME_TIMES,
	BULLETMLNODE_NAME_BULLETREF,
	BULLETMLNODE_NAME_ACTIONREF,
	BULLETMLNODE_NAME_FIREREF,
	BULLETMLNODE_NAME_PARAM,
	BULLETMLNODE_NAME_COUNT,
};

/* BulletMLNode.type */
enum {
	BULLETMLNODE_TYPE_NONE,		/* bulletml */
	BULLETMLNODE_TYPE_VERTICAL,	/* bulletml */
	BULLETMLNODE_TYPE_HORIZONTAL,	/* bulletml */
	BULLETMLNODE_TYPE_AIM,		/* direction */
	BULLETMLNODE_TYPE_ABSOLUTE,	/* direction,speed,horizontal,vertical */
	BULLETMLNODE_TYPE_RELATIVE,	/* direction,speed,horizontal,vertical */
	BULLETMLNODE_TYPE_SEQUENCE,	/* direction,speed,horizontal,vertical */
	BULLETMLNODE_TYPE_COUNT,
};

#define BULLETML_MAX_PARAMS	9	/* <～Ref>フレームあたりの最大<param>数 (調整可。BulletMLの仕様では規定されていません) */

/****************************************************************************
 *	アプリケーションが使用する関数
 ****************************************************************************/

/* BulletML XMLファイルをロード、または、XMLテキストをパースし、ツリーを生成します。
 * [in]
 *	filename_or_xmltext	XMLファイル名、または、XMLテキスト。
 * [out]
 *	戻り値			ツリーのルートの<bulletml>を表すBulletMLNode。
 * [note]
 *	* 不要になったら、この関数が返したBulletMLNodeに対してBulletMLNode_delete()を呼び出し、削除してください。
 *	  自動的に連鎖して、ツリー全体が削除されます。
 *	  アプリケーションは、ツリーの途中のノードに対して、直接、BulletMLNode_delete()を呼び出してはいけません。
 */
BulletMLNode* BulletML_load(const char* filename_or_xmltext);

/* BulletMLツリーを削除します。
 * [note]
 *	- BulletML_load()のコメントを参照してください。
 */
//void BulletMLNode_delete(BulletMLNode* This); → 下で宣言

/* 弾制御を生成します。
 * [in]
 *	userFunc	コールバック関数テーブル。
 *			userFuncにNULLを指定することはできませんが、各エントリにNULLを指定することはできます。
 *			NULLを指定したエントリについては、コールバックされません。
 *	userData	コールバック時に引き渡される、アプリケーション定義の任意の値です。
 *			通常は、弾の実体を表す(ACT*)ポインタ等を指定してください。
 *	bulletNode	アプリケーションが能動的に弾制御を生成する場合、BulletML_load()から返された<bulletml>を表すBulletMLNodeを指定してください。
 *			createBullet()コールバックに応答して受動的に弾制御を生成する場合、createBullet()に渡された<bullet>を表すBulletMLNodeをそのまま指定してください。
 *	params		アプリケーションが能動的に弾制御を生成する場合、NULLを指定してください。
 *			createBullet()コールバックに応答して受動的に弾制御を生成する場合、createBullet()に渡されたparamをそのまま指定してください。
 * [note]
 *	* 不要になったら、BulletMLBullet_delete()を呼び出して削除してください。
 */
//BulletMLBullet* BulletMLBullet_new(const BulletMLUserFunc* userFunc, void* userData, BulletMLNode* bulletNode, const fixed params[/*BULLETML_MAX_PARAMS*/]/*NULL*/); → 下で宣言

/* 弾制御を実行します。
 * [out]
 *	戻り値		全てのActionが完了し、かつ、changeSpeedなどの変化も全て完了していたら、0を返します。
 *			まだ完了していなければ、0以外の値を返します。
 * [note]
 *	* 通常は、BulletMLBullet_run()が0を返したことによって、Bulletアクションの終了を検出し、BulletMLBullet_delete()を呼び出してください。
 *	  ただし、Bulletアクションの終了後に、必ずしも直ちにBulletMLBullet_delete()を呼び出す必要はありません。
 *	  Bulletアクションが終了した後に繰り返しBulletMLBullet_run()を呼び出しても、何もせずに0を返し続けます。
 */
//int BulletMLBullet_run(BulletMLBullet* This); → 下で宣言

/* 弾制御を削除します。
 * [note]
 *	- BulletMLBullet_new()とBulletMLBullet_run()のコメントを参照してください。
 */
//void BulletMLBullet_delete(BulletMLBullet* This); → 下で宣言

/****************************************************************************
 *	BulletMLNode
 ****************************************************************************/

/* BulletMLのXML要素を表すクラスです。
 * - 生成タイミング:
 *	ゲーム初期化時に、BulletML_load()呼び出しによって生成します。
 *	BulletML_load()の戻り値は<bulletml>を表すBulletMLNodeであり、子要素のツリーを持っています。
 *	ゲーム中にひんぱんに、BulletMLNodeのインスタンスを生成することはありません。
 * - 消滅タイミング:
 *	ゲームクリーンアップ時に、<bulletml>を表すBulletMLNodeに対するBulletMLNode_delete()の呼び出しによって消滅します。
 *	子要素のツリーもすべて連鎖して消滅します。
 *	ゲーム中にひんぱんに、BulletMLNodeのインスタンスを消滅することはありません。
 */
struct _BulletMLNode {
	int name;			/* 要素種別 */
	int type;			/* type属性  (bulletml,direction,speed,horizontal,vertical) */
	StdString* label;		/* label属性 (bullet,bulletRef,action,actionRef,fire,fireRef) */
	BulletMLNode* ref;		/* 参照先    (bulletRef,actionRef,fireRef) */
	BulletMLValue* value;		/* 値        (wait,direction,speed,horizontal,vertical,term,times,param) */
	BulletMLNode* firstChild;	/* 先頭の子ノード */
	BulletMLNode* nextSibling;	/* 次の兄弟ノード */
	/*↑BulletMLNode↑*/
};

BulletMLNode* BulletMLNode_new(const char* name);
void BulletMLNode_delete(BulletMLNode* This);
void _BulletMLNode_construct(BulletMLNode* This, const char* name);
void _BulletMLNode_destruct(BulletMLNode* This);
/*public:*/
int BulletMLNode_getName(BulletMLNode* This);
void BulletMLNode_setType(BulletMLNode* This, const char* type);
int BulletMLNode_getType(BulletMLNode* This);
void BulletMLNode_setLabel(BulletMLNode* This, const char* label);
const char* BulletMLNode_getLabel(BulletMLNode* This);
void BulletMLNode_setRef(BulletMLNode* This, BulletMLNode* ref);
BulletMLNode* BulletMLNode_getRef(BulletMLNode* This);
void BulletMLNode_setValue(BulletMLNode* This, const char* value);
BulletMLValue* BulletMLNode_getValue(BulletMLNode* This);
BulletMLNode* BulletMLNode_firstChild(BulletMLNode* This);
BulletMLNode* BulletMLNode_nextSibling(BulletMLNode* This);
void BulletMLNode_addChild(BulletMLNode* This, BulletMLNode* child);
BulletMLNode* BulletMLNode_getChild(BulletMLNode* This, int name);
void BulletMLNode_dump(BulletMLNode* This, int indent);

/****************************************************************************
 *	BulletMLBullet
 ****************************************************************************/

/* ユーザー定義のコールバック関数テーブルを表す構造体です。
 * アプリケーションにて定義し、BulletMLBullet_new()呼び出し時に指定してください。
 * 各コールバック関数の内、NULLを指定したものについては、コールバックされません。
 * <注意!!>
 * - BulletMLBulletはBulletMLUserFuncをコピーせず、ポインタのみを保持します。
 *   アプリケーションは、BulletMLBullet_new()呼び出し後も、BulletMLUserFuncの内容を保持してください。
 *   通常、BulletMLUserFuncの内容を動的に初期化・変更する必要は無いはずなので、定数データ領域に定義するのが適切です。
 */
typedef struct _BulletMLUserFunc {
	void (*createBullet)(void* userData, fixed direction, fixed speed, BulletMLNode* bulletNode, const fixed params[/*BULLETML_MAX_PARAMS*/]);
	void (*setDirection)(void* userData, fixed direction);
	void (*setSpeed)(void* userData, fixed speed);
	void (*setAccelH)(void* userData, fixed accelH);
	void (*setAccelV)(void* userData, fixed accelV);
	void (*vanish)(void* userData);
	fixed (*getRand)(void* userData);
	fixed (*getRank)(void* userData);
	fixed (*getAimDirection)(void* userData);
	fixed (*getDirection)(void* userData);
	fixed (*getSpeed)(void* userData);
	fixed (*getAccelH)(void* userData);
	fixed (*getAccelV)(void* userData);
} BulletMLUserFunc;

/* direction,speed,accelの変化を管理するために、内部使用する構造体です。
 */
typedef struct _BulletMLChange {
	/* <changeDirection|changeSpeed|accel>用 */
	fixed start;	/* 初期値 */
	fixed diff;	/* 変化量 */
	int term;	/* 期間 */
	int cnt;	/* 経過時間 */
	/* <direction|speed|horizontal|vertical type="sequence">用 */
	fixed prev;	/* 前回値 */
} BulletMLChange;

/* <bulletml>または<bullet>を表すBulletMLNodeを基に作成された、Bulletインスタンスです。
 * - 生成タイミング:
 *	ゲーム実行中にアプリケーションが、能動的に<bulletml>を表すBulletMLNodeを指定してBulletMLBullet_new()を呼び出して生成します。
 *	または、BulletMLUserFunc.createBullet()コールバックに応答して、受動的に<bullet>を表すBulletMLNodeを指定してBulletMLBullet_new()を呼び出して生成します。
 * - 消滅タイミング:
 *	どちらの方法で生成した場合も、アプリケーションの判断による任意のタイミングで、BulletMLBullet_delete()を呼び出して消滅します。
 *	通常は、BulletMLBullet_run()が0を返したことによって、Bulletアクションの終了を検出し、BulletMLBullet_delete()を呼び出してください。
 *	ただし上述の条件は必須ではなく、Bulletアクションが終了していなくても、アプリケーションの判断によっていつでもBulletMLBullet_delete()を呼び出して構いません。
 *	たとえば、Bulletアクションが進行中でも、弾が画面外に外れるなど弾自体が消滅するとBulletMLBulletも不要になりますので、BulletMLBullet_delete()を呼び出します。
 */
struct _BulletMLBullet {
	const BulletMLUserFunc* userFunc;	/* ユーザー定義のコールバック関数テーブル */
	void* userData;				/* ユーザー定義のコールバックデータ */
	fixed params[BULLETML_MAX_PARAMS];	/* 直近の<～Ref>フレームの<param>を解決した値 */
	BulletMLChange direction;		/* directionの変化を管理 */
	BulletMLChange speed;			/* speedの変化を管理 */
	BulletMLChange accelH;			/* accel horizontalの変化を管理 */
	BulletMLChange accelV;			/* accel verticalの変化を管理 */
	BulletMLAction* firstAction;		/* 先頭の子アクション。BulletMLAction.nextSiblingへ辿ってツリーを表す (★NOTE: <bullet>の直下に複数の子<action>がある場合、全て同時に起動し並行動作します!!) */
	/*↑BulletMLBullet↑*/
};

BulletMLBullet* BulletMLBullet_new(const BulletMLUserFunc* userFunc, void* userData, BulletMLNode* bulletNode, const fixed params[/*BULLETML_MAX_PARAMS*/]/*NULL*/);
void BulletMLBullet_delete(BulletMLBullet* This);
void _BulletMLBullet_construct(BulletMLBullet* This, const BulletMLUserFunc* userFunc, void* userData, BulletMLNode* bulletNode, const fixed params[/*BULLETML_MAX_PARAMS*/]/*NULL*/);
void _BulletMLBullet_destruct(BulletMLBullet* This);
/*public:*/
const BulletMLUserFunc* BulletMLBullet_getUserFunc(BulletMLBullet* This);
void* BulletMLBullet_getUserData(BulletMLBullet* This);
int BulletMLBullet_run(BulletMLBullet* This);

/****************************************************************************
 *	BulletMLAction
 ****************************************************************************/

/* <action>を表すBulletMLNodeを基に作成された、Actionインスタンスです。
 * - 生成タイミング:
 *	ゲーム実行中にアプリケーションが、能動的または受動的にBulletMLBullet_new()を呼び出したとき、および、BulletMLBullet_run()を呼び出したときに、その内部処理で作成されます。
 *	アプリケーションが、Actionインスタンスの生成タイミングを意識する必要はありません。
 * - 消滅タイミング:
 *	ゲーム実行中にアプリケーションがBulletMLBullet_run()を呼び出したときに、その内部処理でActionが完了したら、自動的に消滅します。
 *	または、アプリケーションがBulletMLBullet_delete()を呼び出したときに、実行中のActionが残っていたら、実行を中断して自動的に消滅します。
 *	アプリケーションが、Actionインスタンスの消滅タイミングを意識する必要はありません。
 */
struct _BulletMLAction {
	fixed params[BULLETML_MAX_PARAMS];	/* 直近の<～Ref>フレームの<param>を解決した値 */
	BulletMLBullet* bullet;			/* この<action>が属する親<bullet>。アクションの処理のターゲットとなります */
	BulletMLNode* pc;			/* 次に実行するノード */
	int wait;				/* <wait>用 */
	int repeat;				/* <repeat><times>用 */
	BulletMLAction* childAction;		/* 動作中の子アクション、または、動作中の子アクションが無ければNULL (★NOTE: <action>の直下に複数の子<action>がある場合、他のノードと同様に逐次動作します!!) */
	BulletMLAction* nextSibling;		/* <bullet>内の複数の子<action>のリンク用。BulletMLBullet.firstActionから辿ってツリーを表す */
	/*↑BulletMLAction↑*/
};

BulletMLAction* BulletMLAction_new(BulletMLBullet* bullet, BulletMLNode* actionNode, const fixed params[/*BULLETML_MAX_PARAMS*/]);
void BulletMLAction_delete(BulletMLAction* This);
void _BulletMLAction_construct(BulletMLAction* This, BulletMLBullet* bullet, BulletMLNode* actionNode, const fixed params[/*BULLETML_MAX_PARAMS*/]);
void _BulletMLAction_destruct(BulletMLAction* This);
/*public:*/
int BulletMLAction_run(BulletMLAction* This);

/****************************************************************************
 *	BulletMLValue
 ****************************************************************************/

/* 式や数値などの抽象基底クラスです。
 */
struct _BulletMLValue {
	const BulletMLValue_vtbl* vptr;
	/*↑BulletMLValue↑*/
};

struct _BulletMLValue_vtbl {
	void (*destruct)(BulletMLValue* This);
	fixed (*calc)(BulletMLValue* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData); /*=0*/
	void (*dump)(BulletMLValue* This); /*=0*/
	/*↑BulletMLValue_vtbl↑*/
};

//BulletMLValue* BulletMLValue_new(); 派生クラスからのみ生成
void BulletMLValue_delete(BulletMLValue* This);
void _BulletMLValue_construct(BulletMLValue* This);
/*virtual*/ void _BulletMLValue_destruct(BulletMLValue* This);

/****************************************************************************
 *	BulletMLNumber
 ****************************************************************************/

/* 数値を表します。
 */
struct _BulletMLNumber /*:BulletMLValue*/ {
	const BulletMLNumber_vtbl* vptr;
	/*↑BulletMLValue↑*/
	fixed value;
	/*↑BulletMLNumber↑*/
};

struct _BulletMLNumber_vtbl {
	void (*destruct)(BulletMLNumber* This);
	fixed (*calc)(BulletMLNumber* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData);
	void (*dump)(BulletMLNumber* This);
	/*↑BulletMLValue_vtbl↑*/
	/*↑BulletMLNumber_vtbl↑*/
};

BulletMLNumber* BulletMLNumber_new(const char** pp);
void BulletMLNumber_delete(BulletMLNumber* This);
void _BulletMLNumber_construct(BulletMLNumber* This, const char** pp);
/*virtual*/ void _BulletMLNumber_destruct(BulletMLNumber* This);
/*public:*/
/*virtual*/ fixed _BulletMLNumber_calc(BulletMLNumber* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData);
/*virtual*/ void _BulletMLNumber_dump(BulletMLNumber* This);

/****************************************************************************
 *	BulletMLVar
 ****************************************************************************/

/* 変数($1～$9,$rand,$rank)を表します。
 */
struct _BulletMLVar /*:BulletMLValue*/ {
	const BulletMLVar_vtbl* vptr;
	/*↑BulletMLValue↑*/
	int id;			/* -1 = $rand, -2 = $rank, 0～8 = $1～$9 */
	/*↑BulletMLVar↑*/
};

struct _BulletMLVar_vtbl {
	void (*destruct)(BulletMLVar* This);
	fixed (*calc)(BulletMLVar* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData);
	void (*dump)(BulletMLVar* This);
	/*↑BulletMLValue_vtbl↑*/
	/*↑BulletMLVar_vtbl↑*/
};

BulletMLVar* BulletMLVar_new(const char** pp);
void BulletMLVar_delete(BulletMLVar* This);
void _BulletMLVar_construct(BulletMLVar* This, const char** pp);
/*virtual*/ void _BulletMLVar_destruct(BulletMLVar* This);
/*public:*/
/*virtual*/ fixed _BulletMLVar_calc(BulletMLVar* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData);
/*virtual*/ void _BulletMLVar_dump(BulletMLVar* This);

/****************************************************************************
 *	BulletMLUnExpr
 ****************************************************************************/

/* 単項演算子(-)を表します。
 */
struct _BulletMLUnExpr /*:BulletMLValue*/ {
	const BulletMLUnExpr_vtbl* vptr;
	/*↑BulletMLValue↑*/
	int op;
	BulletMLValue* value;
	/*↑BulletMLUnExpr↑*/
};

struct _BulletMLUnExpr_vtbl {
	void (*destruct)(BulletMLUnExpr* This);
	fixed (*calc)(BulletMLUnExpr* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData);
	void (*dump)(BulletMLUnExpr* This);
	/*↑BulletMLValue_vtbl↑*/
	/*↑BulletMLUnExpr_vtbl↑*/
};

BulletMLUnExpr* BulletMLUnExpr_new(int op, BulletMLValue* value);
void BulletMLUnExpr_delete(BulletMLUnExpr* This);
void _BulletMLUnExpr_construct(BulletMLUnExpr* This, int op, BulletMLValue* value);
/*virtual*/ void _BulletMLUnExpr_destruct(BulletMLUnExpr* This);
/*public:*/
/*virtual*/ fixed _BulletMLUnExpr_calc(BulletMLUnExpr* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData);
/*virtual*/ void _BulletMLUnExpr_dump(BulletMLUnExpr* This);

/****************************************************************************
 *	BulletMLBinExpr
 ****************************************************************************/

/* 二項演算子(+,-,*,/,%)を表します。
 */
struct _BulletMLBinExpr /*:BulletMLValue*/ {
	const BulletMLBinExpr_vtbl* vptr;
	/*↑BulletMLValue↑*/
	int op;
	BulletMLValue* lhs;
	BulletMLValue* rhs;
	/*↑BulletMLBinExpr↑*/
};

struct _BulletMLBinExpr_vtbl {
	void (*destruct)(BulletMLBinExpr* This);
	fixed (*calc)(BulletMLBinExpr* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData);
	void (*dump)(BulletMLBinExpr* This);
	/*↑BulletMLValue_vtbl↑*/
	/*↑BulletMLBinExpr_vtbl↑*/
};

BulletMLBinExpr* BulletMLBinExpr_new(int op, BulletMLValue* lhs, BulletMLValue* rhs);
void BulletMLBinExpr_delete(BulletMLBinExpr* This);
void _BulletMLBinExpr_construct(BulletMLBinExpr* This, int op, BulletMLValue* lhs, BulletMLValue* rhs);
/*virtual*/ void _BulletMLBinExpr_destruct(BulletMLBinExpr* This);
/*public:*/
/*virtual*/ fixed _BulletMLBinExpr_calc(BulletMLBinExpr* This, const fixed params[/*BULLETML_MAX_PARAMS*/], const BulletMLUserFunc* userFunc, void* userData);
/*virtual*/ void _BulletMLBinExpr_dump(BulletMLBinExpr* This);

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif /*__BLTML_H__*/
