AMXX - Head Shotゲーにするプラグイン

AMXXのプラグインの勉強がてらに作ってみました。
また、この実装は完璧ではないため、バイナリ配布はしていません。

仕様などは後半の説明部分を読んでください。

ソース

/*
使い方
rcon コマンドにて
amx_headshot_on	・・・ヘッドショットのときのみ、ダメージが入る
amx_headshot_off	・・・ヘッドショットモードを解除

*/

#include <amxmodx>
#include <amxmisc>
#include <fun>

// 資源を無限にするフラグ
new bool:headshotonly_flag=false

public plugin_init() { 
	register_plugin("amx_headshot_only","0.0","noob")
	register_event("Damage", "damage_check", "b","2>0")
	register_concmd("amx_headshot_on","amx_headshot_on",ADMIN_LEVEL_A,"---")
	register_concmd("amx_headshot_off","amx_headshot_off",ADMIN_LEVEL_A,"---")
	if (!cvar_exists("sv_dropwpn")) register_cvar("sv_dropwpn", "0" )
} 

public amx_headshot_on(id){
	headshotonly_flag=true;
	console_print(id,"Head shot only mode [ON]")
}

public amx_headshot_off(id){
	headshotonly_flag=false;
	console_print(id,"Head shot only mode [OFF]")
}

public damage_check(id){
	if(!headshotonly_flag)  return PLUGIN_CONTINUE
	new enemy	      = read_data(0) // 攻撃してきた敵
//	new apdamage   = read_data(1) // ?
	new damage     = read_data(2) // ダメージ量
	new damagetype = read_data(3) // ダメージを受けた箇所
	if(damagetype != 1){
		set_user_health(id, damage + get_user_health(id));
		set_hudmessage(0,80,220,-1.0 ,0.25,0, 0.0  , 1.0 , 0.1, 0.2, 2)
		show_hudmessage(enemy,"Not Head shot...")
//		console_print(enemy,"Not Head shot...")
	}

	return PLUGIN_CONTINUE
}

説明

このヘッドショットゲープラグインを実装する考え方は、単純で、
当たった箇所がヘッドでない場合は受けたダメージを回復するだけです。


ダメージを受けたときのアクション名は"Damage"なので、
それをregister_eventでダメージを受けたときの処理damage_check関数をセットします。
register_eventには必ずその対象となったプレイヤーIDが引数として渡されるので、idを忘れずに受け取ります。
また、"Damage"のアクションが発生したときに、いくつかの値が発生します。
この値は、そのregister_eventで設定した関数内でread_data関数を使用することで受け取ることができます。
"Damage"アクションがあった時、read_data関数でそれぞれの数値指定するとそれぞれの値が返ってきます。

0・・・敵のid      1・・・不明(AP?)
2・・・ヘルスダメージ  3・・・ダメージ箇所

1に関してはよくわかりません。
順番的にAP?という感じ。これの他にも値があるかもしれない。
使わない値はあらかじめコメントアウトしています。

ダメージ箇所の値については、以下のとおりです。

0・・・全身  1・・・頭  2・・・胸  3・・・腹
4・・・左腕  5・・・右腕 6・・・左足 7・・・右足

全身については、HEを食らったときなどです。


set_user_healthは引数になった対象IDとヘルス値から対象プレイヤーのヘルス値を設定します。
注意したいのは、ダメージを受けたときに発生するのではなく、ダメージを受けたあとに発生するため、
残りヘルス+受けたダメージ=受ける前のダメージ
この受ける前のダメージをセットしてやれば、擬似的にノーダメージのようにみせかけられます。
現在のヘルス値を得るには、get_user_health関数に対象IDを引数として渡せば返ってきます。


これで一通りの実装は完了ですが、
一応ヘッドショットじゃないとだめだよ、というメッセージを攻撃者へ表示させてみましょう。
それがその後2行の処理です。

set_hudmessageは、show_hudmessageの表示場所を指定します。引数はちょっと複雑ですが、
赤,緑,青,X座標,Y座標,effects,fxtime,表示時間,フェードイン時間,フェードアウト時間,チャンネル
となっています。英語で書いてある部分はよくわかりませんでした。
最初の5つと、最後のチャンネルを指定すれば後はデフォルト値で問題ないです。
チャンネルは他のset_hudmessageと被るとやばいので、出来るだけかぶらないようにしましょう。

show_hudmessageには、送信先ID、書式フォーマットを書きます。
送信先IDを攻撃してきた敵のIDが入っているenemyを指定します。
書式フォーマットには、変数の入った数値や文字列を表示したり、改行などの指定がありますが、
今回はシンプルに「Not head shot.」と表示させるだけなので不要です。


後はコンパイルするだけ。
しかし、コンパイル作業は決まっています。
コンパイル後のプラグインの移動作業もあり、めんどうなことこの上ないです。

なので俺が使っているコンパイル作業も含め自動化するシェルスクリプトを書いておきます。
Linux向けです。やる気があればWindowsでも似たようなことは出来ます。

/steam/〜/cstrike/addons/amxmodx/scripting/c.sh

#!/bin/bash
# AMX Mod X
#
# by the AMX Mod X Development Team
#  originally developed by OLO
#
# This file is part of AMX Mod X.

# new code contributed by \malex\

test -e compiled || mkdir compiled
rm -f temp.txt

for sourcefile in *.sma
do
        amxxfile="`echo $sourcefile | sed -e 's/\.sma$/.amxx/'`"
        echo -n "Compiling $sourcefile ..."
        ./amxxpc $sourcefile -ocompiled/$amxxfile >> temp.txt
        echo "done"
done

#less temp.txt
cat temp.txt
rm temp.txt

~/amxx.sh

cd /steam/〜/cstrike/addons/amxmodx/scripting/
c.sh
mv -f ./compiled/*.amxx ../plugins
cd ~

後はそれぞれに実行権限を与えて、amxx.shを起動するだけでコンパイルと移動作業をしてくれます。
エラーが出た場合も表示されるので安心です。
amxx.shはカレントディレクトリに置いておくとラクです。

@追記

書き忘れましたが、この実装は完璧ではないです。
"ダメージを受けたあと"にDamageのイベントが発生することです。
もしAWPなどの即死にいたるダメージなどの場合、死亡フラグが立ってしまい、
そうなると体力を再セットする関数を使っても無意味になるようです。
その辺についても調べて生きたいと思います。


試す相手がいないため、自分にHEを当てる程度しか試せていない。
BOT入れてもいいんですが、めんどくさくてやってないry
明日あたりにBOT+AMXXが使える鯖を構築しよう。

@さらに追記

headshotのプラグインで実装にミスがありました。
Damageイベントが発生したときのread_data(0)のことで、
正しいはずなのに機能しなかったりしました。
get_user_attacker関数で、ダメージを受けた人から、
ダメージを与えた人、武器、箇所を取得するほうがよさそうです。
修正版 damage_check

public damage_check(id){
	if(!headshotonly_flag)  return PLUGIN_CONTINUE
//	new enemy	   = read_data(0) // ダメージを与えてきた敵
//	new xxxxx   = read_data(1) // ?
	new damage  = read_data(2) // ダメージ量
//	new damagetype = read_data(3) // ダメージを受けた箇所
	new weapon, hitplace
	new attacker = get_user_attacker(id,weapon,hitplace)
	
	if(hitplace != 1){
		set_user_health(id, damage + get_user_health(id));
		set_hudmessage(0 ,80,220,-1.0 ,0.25,0, 0.0  , 1.0 , 0.1, 0.2, 2)
		show_hudmessage(attacker ,"Not Head shot...")
	}
	
	return PLUGIN_CONTINUE
}