PropSpawnプラグイン
クソプラグイン作った
指定したPropを出現させて位置を設定、設置した位置を保存できる
ラウンド開始時に自動でロードする機能付き
マップをカスタムしたりしてどうぞ
以下ソースコード全文
#include <sourcemod> #include <sdktools> new Handle:v_enable = INVALID_HANDLE; new Handle:v_map = INVALID_HANDLE; new g_ent[MAXPLAYERS+1]; //(プレイヤーごとに保存)操作対象のProp new float:g_point[MAXPLAYERS+1]; //(プレイヤーごとに保存)Propの操作単位 public Plugin:myinfo = { //プラグイン情報を記述 name = "[ANY]Prop Spawn", author = "AMG", description = "Propを出したり消したり", version = "", url = "" } //プラグイン起動時 public OnPluginStart(){ v_enable = CreateConVar("sm_prop_enable", "0", "Prop操作モードのオンオフ"); v_map = CreateConVar("sm_prop_autoload", "0", "自動的にPropをロードする"); RegAdminCmd("sm_spawn", Cmd_prop_spawn, 0, "Propを出現させる"); RegAdminCmd("sm_skin", Cmd_prop_skin, 0, "Propのスキンを変更する"); RegAdminCmd("sm_tele", Cmd_prop_tele, 0, "Propを移動させる"); RegAdminCmd("sm_ang", Cmd_prop_ang, 0, "Propの向きを変える"); RegAdminCmd("sm_kill", Cmd_prop_kill, 0, "Propを消去する"); RegAdminCmd("sm_save", Cmd_prop_save, 0, "Propの位置を保存する"); RegAdminCmd("sm_load", Cmd_prop_load, 0, "Propの位置を再現する"); RegAdminCmd("sm_target", Cmd_prop_target, 0, "Propの位置の微調整"); RegAdminCmd("sm_point", Cmd_prop_point, 0, "Propの移動距離を設定"); RegAdminCmd("sm_hp", Cmd_prop_hp, 0, "Propのヘルスを設定する"); //RegAdminCmd("sm_move", Cmd_prop_move, 0, "Propを持ち運ぶ"); //Propのダメージイベントをフックする HookEntityOutput("prop_physics","OnTakeDamage",EntityHook); HookEntityOutput("prop_dynamic","OnTakeDamage",EntityHook); //HookEvent("break_prop", OnBreakProp); HookEvent("teamplay_round_active", OnRoundStart); } //HookEvent ラウンド開始時 public OnRoundStart(Handle:event, const String:name[], bool:dontBroadcast){ if(GetConVarInt(v_map) == 0){ return; } Func_PropLoad(); } //Propにダメージが与えられた時に実行される OnTakeDamage public Action:EntityHook(const char[] output, int caller, int activator, float delay){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } //PrintToChatAll("Entity:%d OutPut:%s Health:%d Activator:%d",caller,output,GetEntProp(caller, Prop_Data, "m_iHealth"),activator); new String:strName[10]; GetEntityClassname(activator,strName,sizeof(strName)); if(StrEqual(strName,"player") == true){ PrintToChat(activator,"TargetEntity:%d",caller); g_ent[activator] = caller; } } //チャットトリガ Propの移動距離を設定 public Action:Cmd_prop_point(client,args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } new String:strCmd[10]; new float:flTemp; GetCmdArg(1,strCmd,sizeof(strCmd)); flTemp = StringToFloat(strCmd); if(FloatCompare(flTemp,0.0) < 1){ PrintToChat(client,"0.1以上の値を指定してください。"); return Plugin_Continue; } g_point[client] = flTemp; PrintToChat(client,"移動距離を%fに設定しました。",g_point[client]); return Plugin_Continue; } //チャットトリガ Prop位置微調整 public Action:Cmd_prop_target(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } //移動量が不正ならば1を代入する if(FloatCompare(g_point[client],0.0) <= 0){ g_point[client] = 1.0; } new String:strCmd[10]; new float:vec[3]; new float:ang[3]; GetCmdArgString(strCmd,sizeof(strCmd)); //数値が来たら対象のEntityIndexを更新する if(StringToInt(strCmd) != 0){ g_ent[client] = StringToInt(strCmd); if(IsValidEntity(g_ent[client]) == false){ PrintToChat(client,"ValidEntity %d",g_ent[client]); } return Plugin_Continue; } //Entityの存在確認 if(IsValidEntity(g_ent[client]) == false){ PrintToChat(client,"ValidEntity %d",g_ent[client]); return Plugin_Continue; } //座標を確保 GetEntPropVector(g_ent[client], Prop_Data, "m_vecOrigin", vec); GetEntPropVector(g_ent[client], Prop_Data, "m_angRotation", ang); //x座標 if(StrEqual(strCmd,"+x") == true){ vec[0] = FloatAdd(vec[0],g_point[client]); } else if(StrEqual(strCmd,"-x") == true){ vec[0] = FloatAdd(vec[0],FloatMul(g_point[client],-1.0)); } //y座標 else if(StrEqual(strCmd,"+y") == true){ vec[1] = FloatAdd(vec[1],g_point[client]); } else if(StrEqual(strCmd,"-y") == true){ vec[1] = FloatAdd(vec[1],FloatMul(g_point[client],-1.0)); } //z座標 else if(StrEqual(strCmd,"u") == true){ vec[2] = FloatAdd(vec[2],g_point[client]); } else if(StrEqual(strCmd,"d") == true){ vec[2] = FloatAdd(vec[2],FloatMul(g_point[client],-1.0)); } //ピッチ(前後回転) else if(StrEqual(strCmd,"+p") == true){ ang[0] = FloatAdd(ang[0],g_point[client]); } else if(StrEqual(strCmd,"-p") == true){ ang[0] = FloatAdd(ang[0],FloatMul(g_point[client],-1.0)); } //ヨー(水平左右回転) else if(StrEqual(strCmd,"l") == true){ ang[1] = FloatAdd(ang[1],g_point[client]); } else if(StrEqual(strCmd,"r") == true){ ang[1] = FloatAdd(ang[1],FloatMul(g_point[client],-1.0)); } //ロール(垂直左右回転) else if(StrEqual(strCmd,"+r") == true){ ang[2] = FloatAdd(ang[2],g_point[client]); } else if(StrEqual(strCmd,"-r") == true){ ang[2] = FloatAdd(ang[2],FloatMul(g_point[client],-1.0)); } //指定の位置に移動 TeleportEntity(g_ent[client], vec, ang, NULL_VECTOR); return Plugin_Continue; } //チャットトリガ Propヘルス設定 public Action:Cmd_prop_hp(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } //Entityの存在確認 if(IsValidEntity(g_ent[client]) == false){ PrintToChat(client,"ValidEntity %d",g_ent[client]); return Plugin_Continue; } new String:strArg[30]; new iHealth; new iDamage; if(args != 1){ PrintToChat(client,"need arg"); } GetCmdArg(1,strArg,sizeof(strArg)); iHealth = StringToInt(strArg); //Propのヘルスを設定する SetEntProp(g_ent[client], Prop_Data, "m_iHealth", iHealth); if(iHealth < 1){ iDamage = 1; } else{ iDamage = 2; } //ヘルスが0以外ならばダメージを受ける 0なら無敵 SetEntProp(g_ent[client], Prop_Data, "m_takedamage", iDamage); } //チャットトリガ Prop消去 public Action:Cmd_prop_kill(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } //Entityの存在確認 if(IsValidEntity(g_ent[client]) == false){ PrintToChat(client,"ValidEntity %d",g_ent[client]); return Plugin_Continue; } AcceptEntityInput(g_ent[client],"Kill"); } //チャットトリガ Prop出現 public Action:Cmd_prop_spawn(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } new String:Model[PLATFORM_MAX_PATH]; new String:Prop[30]; if(args < 1){ PrintToChat(client,"!prop_spawn 'ModelName' 'PropType'"); return Plugin_Continue; } GetCmdArg(1,Model,sizeof(Model)); if(args >= 2){ GetCmdArg(2,Prop,sizeof(Prop)); } else{ //Propタイプが指定されていなければphysics_overrideとする Prop = "prop_physics_override"; } //Entity作成 new ent = Func_PropSpawn(Model,Prop); if(ent == -1){ PrintToChat(client,"Propの生成に失敗しました"); return Plugin_Continue; } //Ent番号を表示させる PrintToChat(client,"Spawn Entity:%d target set",ent); g_ent[client] = ent; new float:vec[3]; new float:ang[] = {0,0,0}; GetClientAbsOrigin(client, vec); TeleportEntity(ent, vec, ang, NULL_VECTOR); return Plugin_Continue; } //関数 Prop出現処理 public Func_PropSpawn(String:Model[], String:Prop[]){ new ent = CreateEntityByName(Prop); if(ent == -1){ return ent; } new String:strName[PLATFORM_MAX_PATH]; //Propにモデルを設定する SetEntPropString(ent, Prop_Data, "m_ModelName", Model); //衝突判定を設定 SetEntProp(ent, Prop_Data, "m_nSolidType",6); //チェックのために名前をつける 同じ名前は付けられない(破壊されていても) Format(strName,sizeof(strName),"prop_test_%d",GetGameTickCount()); SetEntPropString(ent, Prop_Data, "m_iName", strName); //Propをスポーンさせる DispatchSpawn(ent) return ent; } //チャットトリガ Prop移動 public Action:Cmd_prop_tele(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } //Entityの存在確認 if(IsValidEntity(g_ent[client]) == false){ PrintToChat(client,"ValidEntity %d",g_ent[client]); return Plugin_Continue; } new float:vec[3]; new String:temp[25]; GetCmdArg(1,temp,sizeof(temp)); vec[0] = StringToFloat(temp); GetCmdArg(2,temp,sizeof(temp)); vec[1] = StringToFloat(temp); GetCmdArg(3,temp,sizeof(temp)); vec[2] = StringToFloat(temp); TeleportEntity(g_ent[client], vec, NULL_VECTOR, NULL_VECTOR); } /*チャットトリガ Prop持ち運び public Action:Cmd_prop_move(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } //Entityの存在確認 if(IsValidEntity(g_ent[client]) == false){ PrintToChat(client,"ValidEntity %d",g_ent[client]); return Plugin_Continue; } new String:strName[10]; IntToString(client,strName,sizeof(strName)); if(GetEntPropEnt(g_ent[client], Prop_Data, "m_hMoveParent") <= 0){ //クライアント番号で名前をつける SetEntPropString(client, Prop_Data, "m_iName", strName); //親子化処理 SetVariantString(strName); AcceptEntityInput(g_ent[client], "SetParent"); } else{ //親子化解除処理 AcceptEntityInput(g_ent[client], "ClearParent"); } } */ //チャットトリガ Prop回転 public Action:Cmd_prop_ang(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } //Entityの存在確認 if(IsValidEntity(g_ent[client]) == false){ PrintToChat(client,"ValidEntity %d",g_ent[client]); return Plugin_Continue; } new float:ang[3]; new String:temp[25]; GetCmdArg(1,temp,sizeof(temp)); ang[0] = StringToFloat(temp); GetCmdArg(2,temp,sizeof(temp)); ang[1] = StringToFloat(temp); GetCmdArg(3,temp,sizeof(temp)); ang[2] = StringToFloat(temp); TeleportEntity(g_ent[client], NULL_VECTOR, ang, NULL_VECTOR); } //チャットトリガ Propスキン変更 public Action:Cmd_prop_skin(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } //Entityの存在確認 if(IsValidEntity(g_ent[client]) == false){ PrintToChat(client,"ValidEntity %d",g_ent[client]); return Plugin_Continue; } new String:temp[5]; GetCmdArg(1,temp,sizeof(temp)); SetEntProp(g_ent[client], Prop_Data, "m_nSkin", StringToInt(temp)); } //チャットトリガ Prop一覧作成 public Action:Cmd_prop_save(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } Func_PropSearch(1); } //関数 Propを探す public Func_PropSearch(int Mode){ //Mode 1 : Propの位置を保存する //Mode 0 : Propを全て削除する new ent = -1; new String:strClassName[30]; new String:strMap[PLATFORM_MAX_PATH]; new Handle:hFile = INVALID_HANDLE; if(Mode){ GetCurrentMap(strMap,sizeof(strMap)); Format(strMap,sizeof(strMap),"cfg/%s_prop.csv",strMap); //ファイルを作成する(読み込みモード・既存破棄(w)・書き込み可(+)) hFile = OpenFile(strMap,"w+"); if(hFile == INVALID_HANDLE){ PrintToServer("[PropSpawn]ファイルが読み取り専用もしくは開いたままになっていませんか?"); return; } } strClassName = "prop_physics" while ((ent = FindEntityByClassname(ent, strClassName)) != -1) //名前からエンティティを探す { if(Mode){ //恐らく全てoverrideだと思うん Func_Prop_File(ent,hFile,"prop_physics_override"); } else{ GetEntPropString(ent, Prop_Data, "m_iName", strMap, sizeof(strMap)); if(strncmp("prop_test",strMap,9) == 0){ AcceptEntityInput(ent,"Kill"); } } } ent = -1; strClassName = "prop_dynamic" while ((ent = FindEntityByClassname(ent, strClassName)) != -1) //名前からエンティティを探す { if(Mode){ Func_Prop_File(ent,hFile,strClassName); } else{ GetEntPropString(ent, Prop_Data, "m_iName", strMap, sizeof(strMap)); if(strncmp("prop_test",strMap,9) == 0){ AcceptEntityInput(ent,"Kill"); } } } if(Mode){ CloseHandle(hFile); } } //Propの一覧 ファイル書き込み処理 public Func_Prop_File(int ent,Handle:hFile, String:strClassName[]){ /* Propの情報をカンマ区切りリCSV形式で保存する ・モデル名 ・Prop種類 ・位置座標(3要素) ・角度(3要素) ・スキン ・ヘルス ・衝突判定 ・ダメージ有効かどうか */ new float:vec[3]; new float:ang[3]; new String:strName[PLATFORM_MAX_PATH]; GetEntPropString(ent, Prop_Data, "m_iName", strName, sizeof(strName)); if(strncmp("prop_test",strName,9) == 0){ GetEntPropString(ent, Prop_Data, "m_ModelName", strName, sizeof(strName)); GetEntPropVector(ent, Prop_Data, "m_vecOrigin", vec); GetEntPropVector(ent, Prop_Data, "m_angRotation", ang); WriteFileLine(hFile,"%s,%s,%f,%f,%f,%f,%f,%f,%d,%d,%d,%d",strName,strClassName,vec[0],vec[1],vec[2],ang[0],ang[1],ang[2],GetEntProp(ent, Prop_Data, "m_nSkin"),GetEntProp(ent, Prop_Data, "m_iHealth"),GetEntProp(ent, Prop_Data, "m_nSolidType"),GetEntProp(ent, Prop_Data, "m_takedamage")); } } //チャットトリガ Prop再現 public Action:Cmd_prop_load(client, args){ if(GetConVarInt(v_enable) == 0){ return Plugin_Continue; } Func_PropLoad(); } public Func_PropLoad(){ new String:strMap[PLATFORM_MAX_PATH]; new String:strArg[12][PLATFORM_MAX_PATH]; new float:vec[3]; new float:ang[3]; new ent; //現在存在するPropを全て削除する Func_PropSearch(0); GetCurrentMap(strMap,sizeof(strMap)); Format(strMap,sizeof(strMap),"cfg/%s_prop.csv",strMap); new Handle:hFile = OpenFile(strMap,"r"); if(hFile == INVALID_HANDLE){ PrintToServer("[PropSpawn]ファイルが読み取り専用もしくは開いたままになっていませんか? それかファイルがありません。"); return; } while(!IsEndOfFile(hFile)){ //1行読み込む ReadFileLine(hFile,strMap,sizeof(strMap)); //空行でなければ実行する if(StrEqual(strMap,"") == false){ //csvをフィールドごとに配列に入れる if(ExplodeString(strMap, ",", strArg, 12, PLATFORM_MAX_PATH) == 12){ ent = Func_PropSpawn(strArg[0],strArg[1]); if(ent == -1){ PrintToServer("[PropSpawn]Propのロードに失敗しました。"); PrintToServer("%s",strMap); } else{ //Entityの情報を設定する vec[0] = StringToFloat(strArg[2]); vec[1] = StringToFloat(strArg[3]); vec[2] = StringToFloat(strArg[4]); ang[0] = StringToFloat(strArg[5]); ang[1] = StringToFloat(strArg[6]); ang[2] = StringToFloat(strArg[7]); SetEntProp(ent, Prop_Data, "m_nSkin", StringToInt(strArg[8])); SetEntProp(ent, Prop_Data, "m_iHealth", StringToInt(strArg[9])); SetEntProp(ent, Prop_Data, "m_nSolidType", StringToInt(strArg[10])); SetEntProp(ent, Prop_Data, "m_takedamage", StringToInt(strArg[11])); TeleportEntity(ent, vec, ang, NULL_VECTOR); } } else{ PrintToServer("[PropSpawn]フィールド数がおかしいです。"); PrintToServer("%s",strMap); } } } }
Propの操作はbindする必要あり 例
//prop_spawn用 bind "UPARROW" "sm_target +y" bind "LEFTARROW" "sm_target -x" bind "DOWNARROW" "sm_target -y" bind "RIGHTARROW" "sm_target +x" bind "PGUP" "sm_target u" bind "PGDN" "sm_target d" bind "DEL" "sm_target l" bind "END" "sm_target r" bind "INS" "sm_target +p" bind "HOME" "sm_target -p" bind "KP_SLASH" "sm_target +r" bind "KP_MULTIPLY" "sm_target -r"
Propを攻撃すると操作対象をそのPropに移す
後はコマンドのコメント見て
あーあと!moveは上手く動かないからコメントアウトした