ponpoko実験室

3.Quake2のimpulse値を取得するには?

 Quakeのカスタムモジュール界では超ポピュラーだったユーザー用のコマンドimpulse、Quake2でも生きておりました。
 この言葉を初めて耳にする方のために説明しますとコンソールコマンド"impulse"は

impulse n

の形でパラメータnへ任意の値(0〜255)を指定して実行するとimpulse値(impulseコマンド実行時以外は常に0)が1フレームの間だけnへ変化し、次のフレームでは0へ戻るというコマンドです。 なお、ノーマル状態のQuake2ではimpulseコマンドは生ける屍状態で、何の用途にも使われていません。 しかし、impulseへ親しんできたQuakerとしては何としても使ってみたいコマンドなので、今回はimpulse値を取得する方法について説明します。

 ソースp_client.c中にはプレイヤーのために毎フレームごと(ゲームの状態によってはサーバーの1フレーム中に複数回呼び出されることになることも有りうる)に呼び出されるClientThink関数があります。 この関数はサーバーから与えられる情報を元にプレイヤーの挙動を制御(移動その他)する関数で、呼び出される際に与えられる引数のusercmd_t型構造体メンバにimpulse値は含まれています。

 参考のために、usercmd_t型構造体はどのように定義されているのか以下に示します。
typedef struct usercmd_s
{
	byte	msec;
	byte	buttons;
	short	angles[3];
	short	forwardmove, sidemove, upmove;
	byte	impulse;		// remove? この値
	byte	lightlevel;		// light level the player is standing on
} usercmd_t;

酷い扱いですね"remove?"とか言われています。

 それでは実際にどう使うのか使用例を簡単に示して終わりにしたいと思います。impulse値が0以外の場合、その値を表示させるようにしてみましょう。ソースp_client.c中から以下リストのClientThink関数定義位置を探し出し、で示した部分を追加してみてください。
/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame.
==============
*/
void ClientThink (edict_t *ent, usercmd_t *ucmd)
{
	gclient_t	*client;
	edict_t	*other;
	int		i, j;
	pmove_t	pm;

	if( ucmd->impulse != 0 )
	gi.cprintf (ent, PRINT_HIGH, "value \"impulse\" = %3i\n", ucmd->impulse );

	level.current_entity = ent;
	client = ent->client;

	if (level.intermissiontime)
	{
		・
		・
		・
		・

 変更して作成されたgamex86.dllでQuake2を起動したらマルチプレイヤーでゲームをスタートさせ、コンソールから

impulse 120

と打ち込んで実行してみましょう。以下のようにちゃんと表示されましたか?

value "impulse" = 120

 何故マルチプレイヤーモードで実験したかというと、シングルプレイモードでコンソールを開くとプレイヤーの情報は更新されない(ClientThink関数が呼び出されない)のに仮想サーバーのフレーム更新は行われ続けるという状態なるからです。 適当なキーへimpulseコマンドをバインドするか、コンソールからimpulseコマンドを入力してリターンを押すとほぼ同時にコンソールを閉じればプログラムから返答がちゃんと戻ってきます。

 あとはこのインパルス値を使ってBOTクン発生やフック選択をやればいいと思います。たぶん問題ないとは思うんですが?
e-mail:ponpoko@axcx.com