第六章(´・ω・`)おばあちゃん、クローン武器を作ってみるわよ☆



・武器っつっても

武器を追加するといってもいきなり「拳から竜が飛び出す」とかいう無謀なプランやめてよ〜!
無難に既存武器のクローンを作ってみましょう。

・既存武器ソースのコピーと編集

以下のファイルをコピーして・・・(同じ名前のファイルが別のフォルダにもありますがそれじゃありません、注意してください)
C:\Bodycon\src\game_shared\hl2mp\weapon_357.cpp

こんな名前のファイルを作ってください。
C:\Bodycon\src\game_shared\hl2mp\weapon_gero.cpp

そしてこのファイルをhlclientプロジェクト両方 に追加します。
追加方法はファイルをソリュションエクスプローラ上フォルダアイコンへファイルをドラッグ&ドロップするだけです。
コピー元のweapon_357.cppと同じWeaponsフォルダがいいですね。


追加したら以下の例で赤く記されている個所を書き換えてください。
「え〜!面倒臭いよ〜」と思ったらこっからどうぞweapon_gero.cpp
//========= Copyright ゥ 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================//

#include "cbase.h"
#include "npcevent.h"
#include "in_buttons.h"

#ifdef CLIENT_DLL
	#include "c_hl2mp_player.h"
#else
	#include "hl2mp_player.h"
#endif

#include "weapon_hl2mpbasehlmpcombatweapon.h"

// クライアントのDLLでは実際のクラス名がC_〜になるようにする
#ifdef CLIENT_DLL
#define CWeaponGero C_WeaponGero
#endif

//-----------------------------------------------------------------------------
// CWeaponGero
//-----------------------------------------------------------------------------

class CWeaponGero : public CBaseHL2MPCombatWeapon
{
	// 親クラス(スーパークラス)名称をBaseClass
	// 自身のクラス名称をThisClassで表記できるのはこのマクロを
	// 呼んでいるから
	DECLARE_CLASS( CWeaponGero, CBaseHL2MPCombatWeapon );
public:

	CWeaponGero( void );

	void	PrimaryAttack( void );

	// ネットワーククラスを扱うためのメンバ等を宣言
	// クライアントはクライアントクラス
	DECLARE_NETWORKCLASS(); 
	// 予測値テーブルを扱うためのメンバ等を宣言
	DECLARE_PREDICTABLE();

#ifndef CLIENT_DLL
// 武器携行時の挙動上書きリストを扱うためのメンバ等を定義
	DECLARE_ACTTABLE();
#endif

private:
	
	CWeaponGero( const CWeaponGero & );
};

// サーバ、クラインアントそれぞれネットワーククラスが作成され、
// このクラスへ関連付けられる
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGero, DT_WeaponGero )

// サーバーからクライアントに提供される情報テーブルを作成
// BEGIN〜ENDだけならば各武器共通の基本的な情報のみがテーブル
// に組み込まれる
// weapon_crossbow.cppのCNetworkVarマクロで宣言されている
// メンバ変数を参考にするとよい
BEGIN_NETWORK_TABLE( CWeaponGero, DT_WeaponGero )
END_NETWORK_TABLE()

// サーバー側で更新されなくともクライアント側で予測値として
// 扱いたい値をBEGIN〜END間に記述
// weapon_crossbow.cppのCNetworkVarマクロで宣言されている
// メンバ変数を参考にするとよい
BEGIN_PREDICTION_DATA( CWeaponGero )
END_PREDICTION_DATA()

// エンティティ名称とこのクラスを関連付ける
LINK_ENTITY_TO_CLASS( weapon_gero, CWeaponGero );

// 武器クラスにて使用する諸々のデータ(サウンド、モデル)
// をキャッシュへ読込むためにエンティティ名称を登録
// キャッシュするデータの定義はMODフォルダ下にある
// ./script/[武器エンティティ名].txt
// に記述された内容が参照される
// このクラスの場合はweapon_gero.txtが参照される
PRECACHE_WEAPON_REGISTER( weapon_gero );


#ifndef CLIENT_DLL
// 武器携行時の挙動上書きリスト定義
acttable_t CWeaponGero::m_acttable[] = 
{
	{ ACT_HL2MP_IDLE,			ACT_HL2MP_IDLE_PISTOL,		false },
	{ ACT_HL2MP_RUN,			ACT_HL2MP_RUN_PISTOL,			false },
	{ ACT_HL2MP_IDLE_CROUCH,		ACT_HL2MP_IDLE_CROUCH_PISTOL,		false },
	{ ACT_HL2MP_WALK_CROUCH,		ACT_HL2MP_WALK_CROUCH_PISTOL,		false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,	false },
	{ ACT_HL2MP_GESTURE_RELOAD,		ACT_HL2MP_GESTURE_RELOAD_PISTOL,	false },
	{ ACT_HL2MP_JUMP,			ACT_HL2MP_JUMP_PISTOL,		false },
	{ ACT_RANGE_ATTACK1,			ACT_RANGE_ATTACK_PISTOL,		false },
};

// 武器携行時の挙動リスト登録
IMPLEMENT_ACTTABLE( CWeaponGero );

#endif

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CWeaponGero::CWeaponGero( void )
{
	m_bReloadsSingly	= false;
	m_bFiresUnderwater	= false;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponGero::PrimaryAttack( void )
{
	// Only the player fires this way so we can cast


更にhlプロジェクトのソリューションエクスプローラで hl2mp_player.cppを探し出し、210行目へ以下の赤く記した 行を挿入してくらはい。これでスポーンした直後にweapon_geroが持てます。
	GiveNamedItem( "weapon_smg1" );
	GiveNamedItem( "weapon_frag" );
	GiveNamedItem( "weapon_physcannon" );
	GiveNamedItem( "weapon_gero" );


変更が終わったらhlclient両プロジェクトの ビルドを行ってくださいな。

・武器クラスのコード記述パターン
上のソース上のコメントでも書いてあるように以下のマクロは必ず記述すると 思ってよいでしょう。
DECLARE_CLASS
DECLARE_NETWORKCLASS
DECLARE_PREDICTABLE
DECLARE_ACTTABLE
IMPLEMENT_NETWORKCLASS_ALIASED
BEGIN_NETWORK_TABLE
〜END_NETWORK_TABLE
BEGIN_PREDICTION_DATA
〜END_PREDICTION_DATA
LINK_ENTITY_TO_CLASS
PRECACHE_WEAPON_REGISTER
IMPLEMENT_ACTTABLE

NETWORK_TABLEやPREDICTION_DATAの活用はクロスボウ(weapon_crossbow.cpp) で見ることができますね。
武器を使って攻撃した際の処理は一旦クライアント側で動作を予測した 処理を進行させといて後のサーバ側からの応答と照合して辻褄を合わせている はずです。いくつか上の親クラス(CBaseAnimating)ではそこらへんのPREDICTION_DATAが 色々用意されているのが分かります。

・武器スクリプトの準備
さて、即ゲーム起動したいところですが、そうはイカの熟年離婚。
PRECACHE_WEAPON_REGISTERのコメントにも書いてあるようにスクリプト の準備が必要なんです。

スクリプトの置き場所はMODフォルダのscriptsフォルダ下になります。そこにある 以下のファイルをコピーして・・・
C:\Program Files\Valve\Steam\SteamApps\SourceMods\Bodycon\scripts\weapon_357.txt

こんな名前のファイルを作ってください。
C:\Program Files\Valve\Steam\SteamApps\SourceMods\Bodycon\scripts\weapon_gero.txt

weapon_gero.txtをテキストエディタで開き、先頭部分を以下に赤く 記したように書き換えてください。
WeaponData
{
	// Weapon data is loaded by both the Game and Client DLLs.
	"printname"	"#HL2_GeroGun"
	"viewmodel"	"models/weapons/v_irifle.mdl"
	"playermodel"	"models/weapons/w_irifle.mdl"
	"anim_prefix"	"unko"
	"bucket"		"5"
	"bucket_position"	"0"

	"clip_size"	"20"
	"default_clip"	"6"
	"primary_ammo"	"357"
	"secondary_ammo"	"None"

	"weight"		"10"
	"item_flags"	"0"

	"damage"		"5"


何の設定かというと。
printname ゲーム画面の上にある、なんですか、あの〜武器を選択するところ。 仮に「武器選択スロット」と呼びます。あそこに表示する武器の名称です。
viewmodel プレイヤー自身から武器を見た際に使用されるモデル(ビューモデル)のファイル名。
playermodel マップ上に転がってたり他のプレイヤーが使用しているのを見た際に使用されるモデル(ワールドモデル)のファイル名。
anim_prefix 今のところ使用目的がモヤモヤとしか分からない、エンジンインターフェイスから モデルに対するアクションシーケンスのリストを引っ張ってきてその中から該当する アクションの番号をピックアップするためのキーワードの接尾辞に使用されていると思われる。 prefixじゃなくてsuffixじゃないか?
たぶん自分の好きなように指定しちゃっていいと思うんだけど。
bucket 武器選択スロットで横方向に左から0ベースに数えて何番目のスロットに武器アイコンを配置するかを指定。
0〜5で指定。6以上を指定しても5になっちゃう。
bucket_position bucketで指定したスロット内で縦方向へ0ベースに数えて何番目に武器アイコンを配置するかを指定。
但し同一スロットに自分よりbucket_positionの小さい武器が存在しない状態では上詰めになる。
clip_size プライマリ攻撃用弾倉に何発装填できるかの指定。
clip2_size セカンダリ攻撃用弾倉に何発装填できるかの指定。
default_clip プライマリ攻撃用弾倉に初期状態で装填されている弾数。
default_clip2 セカンダリ攻撃用弾倉に初期状態で装填されている弾数。
weight 武器が選択される優先度。指定値が高い程、武器の自動切換えで選択されやすくなる。
item_flags 特殊な仕様の武器へフラグ設定を行う。(グレネードのように使い切った際にスロット上から消える等)。
damage 武器のダメージ。
showusagehint TF2で使うそうです。
autoswitchto 1に指定すると武器の自動切換え発生時にこの武器を持っていたら絶対選ばれる?
autoswitchfrom 1に指定するとこの武器の使用中に他の武器や弾薬なりを拾うとその武器に切り替わってしまう?
BuiltRightHanded 1に指定するとこの武器が右手仕様であることを示す。
AllowFlipping 1に指定すると強制的にこの武器で左手/右手の切り替えを許す。
MeleeWeapon 1に指定するとこの武器が弾薬不要の近接攻撃武器であることを示す。
でもガッポイスティックのスクリプトにそんなもん書いてないじゃん。いらねえんじゃねえの?
primary_ammo プライマリ攻撃用の弾薬名称。
要らない場合は"None"と書く、もしくはなんも書かない。
secondary_ammo セカンダリ攻撃用の弾薬名称。
要らない場合は"None"と書く、もしくはなんも書かない。


・レッツゴー
それではゲーム開始です。

(´・ω・`)スロット6にゲロ銃キターーーー!


見よ、この辛気臭い火力を!バーン、バーン!

(´・ω・`)つ次へ