alchemistarkの日記

やったことのメモ

Propの出現と破壊可能にする方法

ゴリゴリ書いてたのでとりあえず全部貼る。

public Action:Cmd_prop(client, args){

	new ent = CreateEntityByName("prop_dynamic");
	new filter;
	new String:temp[255];
	

	//フィルター関係///////////////////////////
	
	while ((filter = FindEntityByClassname(filter, "filter_activator_tfteam")) != -1){
		GetEntPropString(filter, Prop_Data, "m_iGlobalname", temp,255);
		if(StrEqual(temp,"prop_filter")){
			//既にフィルターが生成されていた場合、削除する
			AcceptEntityInput(filter, "Kill");
		}
	}
	
	filter = CreateEntityByName("filter_activator_tfteam");	//フィルターを作成する
	SetEntProp(filter, Prop_Data, "m_iTeamNum",TFTeam_Blue);	//フィルター対象チームを設定
	
	DispatchSpawn(filter);	//スポーンさせる	
	
	//フィルター名を設定する
	SetEntPropString(filter, Prop_Data, "m_iGlobalname", "prop_filter");

	//Propにフィルターを設定する
	//フィルター名とフィルターEntityが両方必要?
	SetEntPropString(ent, Prop_Data, "m_iszDamageFilterName","prop_filter");
	
	//PropにフィルターEntityを設定
	SetEntPropEnt(ent, Prop_Data, "m_hDamageFilter",filter);
	
	//Prop関係//////////////////////////////////////
	
	//Propのダメージイベントをフックする
	HookSingleEntityOutput(ent,"OnTakeDamage",EntityHook,false);
	
	//Propにモデルを設定する
	SetEntPropString(ent, Prop_Data, "m_ModelName", "models/props_badlands/barrel_flatbed01.mdl");
	//衝突判定を設定
	SetEntProp(ent, Prop_Data, "m_nSolidType",6);
	
	//Propをスポーンさせる
	DispatchSpawn(ent);
	
	//Propのヘルスを設定する
	SetEntProp(ent, Prop_Data, "m_iHealth", 200);
	
	//Propがダメージを受けるようにする
	SetEntProp(ent, Prop_Data, "m_takedamage", 2, 1);	//Mortal
	
	
	//適当な位置に出現させる
	new float:vec[3];
	GetClientAbsOrigin(client, vec);
	TeleportEntity(ent, vec, NULL_VECTOR, NULL_VECTOR);
	
}

public EntityHook(const char[] output, int caller, int activator, float delay){
	PrintToChatAll("%d",GetEntProp(caller, Prop_Data, "m_iHealth"));
}

大体コメントの通り
寝て良いよ

SetEntProp(ent, Prop_Data, "m_nSolidType",6);の値が6なのは何故か分かってない
一応プロパティのCollisionsの値がUse VPhysicsの時6になる。
KeyValueのキー名はsolid。

破壊可能にするだけならヘルスを設定してMortal化するだけでいいはず
ただし破壊された時何も表示せずただ消えるだけなので、破壊時にパーティクルを表示する等の配慮が必要。

フィルターは指定チームのみダメージを与えられるように設定してるので、誰でも壊せるならフィルター自体不要
なるべくフィルターには変な名前付けてマップ既存のフィルターと重複しないように注意した方がいいと思うけど大丈夫じゃないかな

あと言うまでもないけどTeleportEntityの座標がクライアントの位置なのでそのまま呼ぶと自分がPropにハマるから注意。

prop_dynamic - Valve Developer Community
filter_activator_tfteam - Valve Developer Community


追記
prop_physics_overrideを呼び出した場合、何故かHookSingleEntityOutputが上手く動作しないので
HookEntityOutputを使用した方がいいかも。この場合Entityの番号を保存しておくかユニークな名称を付けておく必要があるのでかなりめんどくさい。

prop_physics_override - Valve Developer Community

ていうかね!違いが全然分かってないんだよね!!!
prop_physics→モデル側で対応が必要
prop_physics_multiplayer→わからない モデルが動作中はプレイヤーがすり抜けてしまう?(モデルが静止するとCollisionが復活するのでプレイヤーが埋まる)
prop_physics_override→physics非対応モデルをphysics化?以降Entityのクラス名はprop_physicsになる
prop_physics_respawnable→知らない子です

パーティクルについて

完全に詰んだので書いておく。

まず基本的にこれ。
kimoto.hatenablog.com

これを使って決闘アイコンを表示したい。
んで表示したパーティクルをKill等で削除したいんだけど消えない。
Entityは消えている。決闘アイコンだけ宙に浮いたままになる。
なお1度も視認しなかったプレイヤーや消した後にjoinしたプレイヤーからは見えない。
クライアント側の問題?

解決案?
追従解除してマップのどっかの座標にふっ飛ばしてから消すとか


追記
アンユエフェクト出してみたら消えた
決闘アイコンもエフェクトアニメーションだけ消えるので、どうやらアニメーション設定されていないパーツが有る場合消えなくなる模様。

すごくどうでもいいことに3日ぐらい使った

NPP_SAVE
powershell "$0 = cat \"$(FULL_CURRENT_PATH)\" -Encoding UTF8;$1 = $0 -match \"#define BUILD\";$1 = $1.GetValue(0);$2 = $1.IndexOf(\"(\")+1;$3 = $1.LastIndexOf(\")\")-$2;$2 = $1.substring($2,$3);$3 = [int]$2 + 1;$0 -replace (\"build\($2\)\"),(\"build($3)\") | Set-Content \"$(FULL_CURRENT_PATH)\" -Encoding UTF8"
spcomp.exe "$(FULL_CURRENT_PATH)"
powershell copy $(NAME_PART).smx addons\sourcemod\plugins\ -force
powershell move $(NAME_PART).smx addons\sourcemod\plugins\ -force
powershell copy $(FULL_CURRENT_PATH) addons\sourcemod\scripting\ -force

これなーんだ

元々Notepad++でコンパイラにsp叩き込むようにしてたんだけど、
それに加えてspとsmxをしかるべき場所にコピーするようにしておいた

ついでにコード上で

#define BUILD = "build(0)"

public Plugin:myinfo = 
{
	name = "",
	author = "",
	description = "",
	version = BUILD,
	url = ""
}

って書いとくとコンパイルする度にpowershellでビルド回数を増やしていくという…
うん何やってんだ僕は…
んでそれを1行で叩き込んでると言うね もうね アホかと

PowerShellさんがスクリプトファイルをデフォルトで実行してくれないからです
あとNppExecで動かしたいってのもありますん
以下改行したやつ

$0 = cat "$(FULL_CURRENT_PATH)" -Encoding UTF8
$1 = $0 -match "#define BUILD"
$1 = $1.GetValue(0)
$2 = $1.IndexOf("(")+1
$3 = $1.LastIndexOf(")")-$2
$2 = $1.substring($2,$3)
$3 = [int]$2 + 1
$0 -replace ("build\($2\)"),("build($3)") | Set-Content "$(FULL_CURRENT_PATH)" -Encoding UTF8

はい、何やってんだろうね
寝て良いよ

TF2 セントリーガンの所有者を確認する

多分これ。

Member: m_hBuilder (offset 2276) (type integer) (bits 21) (Unsigned)

他にも使えそうなのいくつか。実際に中身確認してないから本当にそうか分からないけど、名称から予想。
m_bPlayerControlled:ラングラーで操作中かどうか?
m_bBuilding:建造中かどうか?

他の建造物も多分同じプロパティ持ってるとは思う。


試してみないと分からないけど、設置してすぐ所有者を消したら
2つ目3つ目のセントリーを置ける…かもしれない?

TF2 死を回避する方法

無敵化ではなく、ヘルスが0になったけどそのまま戦い続けるようにする方法。

引っ掛けるイベントはplayer_hurt
player_deathはやっぱりダメだった。よってplayer_deathイベントの情報は持ってこれない…

HookEvent("player_hurt", OnPlayerHurt,EventHookMode_Pre);
new client = GetClientOfUserId(GetEventInt(event, "userid"));
if(GetEventInt(event, "health") == 0){
	SetEntityHealth(client,1);
}

"health"の値はマイナスにはならないので安心して0でチェックして良い
ヘルスを最大値にしようと思ったらクラスをチェックしてクラスの最大値を直接指定する必要がある

player_deathが発生しないので、スコアは入らないしキルもデスもカウントが増えない点に注意。
イベントをFireしてもダメなんかな?多分ダメだと思うけど。


customの値一覧。
player_hurtの"custom"とplayer_deathの"customkill"で同じ値出てるから多分一緒だと思う。

…ヘッドショットが1でバックスタブが2なのは確認したし、火炎放射器と延焼ダメージが3なのも間違いない
けどライフルのボディショットが種類にかかわらず11で、小便銃が14(追記:ヒットマンズ・ヒートメーカーは51が出る。TF_CUSTOM_HEADSHOT_DECAPITATION)
分からぬ。
下記のリストは参考までに。

// Custom kill identifiers for the customkill property on the player_death event
enum {
	TF_CUSTOM_HEADSHOT = 1,
	TF_CUSTOM_BACKSTAB,
	TF_CUSTOM_BURNING,
	TF_CUSTOM_WRENCH_FIX,
	TF_CUSTOM_MINIGUN,
	TF_CUSTOM_SUICIDE,
	TF_CUSTOM_TAUNT_HADOUKEN,
	TF_CUSTOM_BURNING_FLARE,
	TF_CUSTOM_TAUNT_HIGH_NOON,
	TF_CUSTOM_TAUNT_GRAND_SLAM,
	TF_CUSTOM_PENETRATE_MY_TEAM,
	TF_CUSTOM_PENETRATE_ALL_PLAYERS,
	TF_CUSTOM_TAUNT_FENCING,
	TF_CUSTOM_PENETRATE_HEADSHOT,
	TF_CUSTOM_TAUNT_ARROW_STAB,
	TF_CUSTOM_TELEFRAG,
	TF_CUSTOM_BURNING_ARROW,
	TF_CUSTOM_FLYINGBURN,
	TF_CUSTOM_PUMPKIN_BOMB,
	TF_CUSTOM_DECAPITATION,
	TF_CUSTOM_TAUNT_GRENADE,
	TF_CUSTOM_BASEBALL,
	TF_CUSTOM_CHARGE_IMPACT,
	TF_CUSTOM_TAUNT_BARBARIAN_SWING,
	TF_CUSTOM_AIR_STICKY_BURST,
	TF_CUSTOM_DEFENSIVE_STICKY,
	TF_CUSTOM_PICKAXE,
	TF_CUSTOM_ROCKET_DIRECTHIT,
	TF_CUSTOM_TAUNT_UBERSLICE,
	TF_CUSTOM_PLAYER_SENTRY,
	TF_CUSTOM_STANDARD_STICKY,
	TF_CUSTOM_SHOTGUN_REVENGE_CRIT,
	TF_CUSTOM_TAUNT_ENGINEER_SMASH,
	TF_CUSTOM_BLEEDING,
	TF_CUSTOM_GOLD_WRENCH,
	TF_CUSTOM_CARRIED_BUILDING,
	TF_CUSTOM_COMBO_PUNCH,
	TF_CUSTOM_TAUNT_ENGINEER_ARM,
	TF_CUSTOM_FISH_KILL,
	TF_CUSTOM_TRIGGER_HURT,
	TF_CUSTOM_DECAPITATION_BOSS,
	TF_CUSTOM_STICKBOMB_EXPLOSION,
	TF_CUSTOM_AEGIS_ROUND,
	TF_CUSTOM_FLARE_EXPLOSION,
	TF_CUSTOM_BOOTS_STOMP,
	TF_CUSTOM_PLASMA,
	TF_CUSTOM_PLASMA_CHARGED,
	TF_CUSTOM_PLASMA_GIB,
	TF_CUSTOM_PRACTICE_STICKY,
	TF_CUSTOM_EYEBALL_ROCKET,
	TF_CUSTOM_HEADSHOT_DECAPITATION,
	TF_CUSTOM_TAUNT_ARMAGEDDON,
	TF_CUSTOM_FLARE_PELLET,
	TF_CUSTOM_CLEAVER,
	TF_CUSTOM_CLEAVER_CRIT,
	TF_CUSTOM_SAPPER_RECORDER_DEATH,
	TF_CUSTOM_MERASMUS_PLAYER_BOMB,
	TF_CUSTOM_MERASMUS_GRENADE,
	TF_CUSTOM_MERASMUS_ZAP,
	TF_CUSTOM_MERASMUS_DECAPITATION,
	TF_CUSTOM_CANNONBALL_PUSH,
	TF_CUSTOM_TAUNT_ALLCLASS_GUITAR_RIFF,
	TF_CUSTOM_THROWABLE,
	TF_CUSTOM_THROWABLE_KILL,
	TF_CUSTOM_SPELL_TELEPORT,
	TF_CUSTOM_SPELL_SKELETON,
	TF_CUSTOM_SPELL_MIRV,
	TF_CUSTOM_SPELL_METEOR,
	TF_CUSTOM_SPELL_LIGHTNING,
	TF_CUSTOM_SPELL_FIREBALL,
	TF_CUSTOM_SPELL_MONOCULUS,
	TF_CUSTOM_SPELL_BLASTJUMP,
	TF_CUSTOM_SPELL_BATS,
	TF_CUSTOM_SPELL_TINY,
	TF_CUSTOM_KART,
	TF_CUSTOM_GIANT_HAMMER,
	TF_CUSTOM_RUNE_REFLECT,
	TF_CUSTOM_DRAGONS_FURY_IGNITE,
	TF_CUSTOM_DRAGONS_FURY_BONUS_BURNING,
	TF_CUSTOM_SLAP_KILL,
	TF_CUSTOM_CROC,
	TF_CUSTOM_TAUNTATK_GASBLAST,
};

無いと思ったらあった

EntityのOutputをFireする関数。
開発版(1.9系)じゃないと使えない。

github.com

/**
 * Fire a named output on an entity.  
 *
 * After completion (successful or not), the current global variant is re-initialized.
 *
 * @param caller	Entity index from where the output is fired.
 * @param output	Output name.
 * @param activator	Entity index which initiated the sequence of actions (-1 for a NULL entity).
 * @param delay		Delay before firing the output.
 * @error		Invalid entity index or no mod support.
 */
native void FireEntityOutput(int caller, const char[] output, int activator=-1, float delay=0.0); 

例えば

public Action:Cmd_setupend(client, args){
	new ent = -1;
	ent = FindEntityByClassname(ent, "team_round_timer");
	
	if(ent == -1){
		return false;
	}
	
	FireEntityOutput(ent,"OnSetupFinished");
	
}

とかするとセットアップ中にセットアップ終了時のOutputをFireするのでゲートが開く。
あくまでFireするだけなので、セットアップのタイマーは止まらないしそのまま平気でセットアップが続行。
けどゲート開いてるから青はどんどん出て行くでござる。これはひどい

TF2 ItemDB プラグイン

SourceModでアイテム(武器等を含む)情報をDB化して他プラグインから利用できるようにするプラグイン
TF2ItemsInfoというプラグインが以前その役割を行っていたのですが、更新されておらず(しかも現状動作していない)
TF2ItemDBがその役目を引き継いでいます。

TF2ItemDBも開発中で、特にTF2ItemsInfoとの置き換えに必要なtf2idb_tf2ii_compatがソースしか無かったりして色々とアレ。

とりあえず簡単に情報のまとめとインストール方法を。


[TF2] TF2 Item DB (replaces tf2itemsinfo) - AlliedModders

AlliedModdersのフォーラムページ。


GitHub - FlaminSarge/tf2idb: TF2 Item DB ( https://forums.alliedmods.net/showthread.php?t=255885 )

GitHubのページ。


フォーラムページからもプラグインは落とせますが、現在ジャングルアプデ絡みで更新が続いているので
念の為GitHubからソースをコンパイルした方がいいかもです。


どうせtf2idb_tf2ii_compatもコンパイルしなきゃならないので…
tf2idb/tf2idb_tf2ii_compat.sp at master · FlaminSarge/tf2idb · GitHub

とりあえずこれで必要なプラグイン2つが準備できました。


次に、DBを作成します。
なんでプラグインで自動的に作ってくれないの?*1

フォーラムのDLの所からtf2idb.zipをダウンロードし、
任意の場所に解凍、tf2idb.pyをテキストエディタで開いて1行目をTF2のsrcdsのインストールパスを記入*2
Python2をインストールし、実行してください。

と、言いたい所ですが
少なくとも僕はこれで有効なDBが作成されませんでした。
srcdsを起動して、起動時にtf2idbがクラッシュしてたら失敗です。sm listでもロードできてない事が確認できると思います。
もし上手く行ってたら教えて下さい。


追記:GitHubにあるtf2idb.pyが最新です。そちらのpyをDLし実行すると、pyと同じところにDBが作成されます。pyの編集は不要です
ですが現時点ではやはりジャングルアプデ武器は使えない模様。*3


上手く行かなかったら、フォーラムにが居るので有難くいただきます。
AlliedModders - View Single Post - [TF2] TF2 Item DB (replaces tf2itemsinfo)
このDBをaddons/sourcemod/data/sqliteに置いて、再度srcdsを起動してください。
tf2idbが読み込めていたら成功です。お疲れ様でした。


TF2GiveWeaponプラグイン等を使用の方は、ロックンロードの装弾数が直っていたり、火炎放射器の射程が正常になっているのが確認できると思います。
つーかTF2ItemsInfoがDB更新してくれないせいでジャングルアプデ後火炎放射器の射程が0になってて軍拡鯖生存の危機でしたよ。
前の記事のBOT自殺事件も込みで本当に辛かった…

*1:まぁそれやってメモリリーク起こして更新しなくなったTF2IIってプラグインがあるんですけどね

*2:2行目と3行目で必要なパスを得る為に1行目に連結させてるの考慮してね

*3:装備できるし弾も出るのですが、弾薬箱を拾うことができずロッカーに触れるとクライアントが落ちる