Помощ преработка Spec Bot Plugin

Въпроси и проблеми свързани с AMXModX.
Аватар
atmax
Извън линия
Потребител
Потребител
Мнения: 492
Регистриран на: 22 Мар 2018, 15:06
Се отблагодари: 37 пъти
Получена благодарност: 43 пъти

Помощ преработка Spec Bot Plugin

Мнение от atmax » 04 Фев 2021, 17:19

Лол.. Този лог трябваше да го покажеш още в началото, като цяло някой пипал ли е тези плъгини, защото съдейки по грешката, някак си запазваш клиентска информация без даже да отваряш nvault файла, съмнява ме OciXcrom да е допуснал такава грешка, а и никой до сега не се е оплакал с подобни грешки в логовете.. А може би не затваряш правилно vault файла nvault_close трябва да се извика в plugin_end() !
Лесните решения, които да пробваш са:
1. Провери в data папката за нещо липсващо.
2. Спри сървъра, изтрии vault файловете за тези плъгини и го пусни пак.
Rest in peace my friend I always will remember you! 🖤👊

Аватар
Siska
Извън линия
Потребител
Потребител
Мнения: 771
Регистриран на: 03 Дек 2019, 22:29
Местоположение: Bedrock
Се отблагодари: 157 пъти
Получена благодарност: 48 пъти
Обратна връзка:

Помощ преработка Spec Bot Plugin

Мнение от Siska » 05 Фев 2021, 13:17

atmax написа: 04 Фев 2021, 17:19 Лол.. Този лог трябваше да го покажеш още в началото, като цяло някой пипал ли е тези плъгини, защото съдейки по грешката, някак си запазваш клиентска информация без даже да отваряш nvault файла, съмнява ме OciXcrom да е допуснал такава грешка, а и никой до сега не се е оплакал с подобни грешки в логовете.. А може би не затваряш правилно vault файла nvault_close трябва да се извика в plugin_end() !
Лесните решения, които да пробваш са:
1. Провери в data папката за нещо липсващо.
2. Спри сървъра, изтрии vault файловете за тези плъгини и го пусни пак.
Проверих за липсващи файлове от тези два плъгина, но всичко е там. Изтрих и файловете , които ми каза , но виж пак изписва това :

Код за потвърждение: Избери целия код

L 02/05/2021 - 13:10:24: [nVault] Invalid vault id: 0

L 02/05/2021 - 13:10:24: [AMXX] Displaying debug trace (plugin "crx_bestplayer.a
mxx", version "unknown")
L 02/05/2021 - 13:10:24: [AMXX] Run time error 10: native error (native "nvault_
get")
L 02/05/2021 - 13:10:24: [AMXX] [0] crx_bestplayer.sma::use_vault (line 400)
L 02/05/2021 - 13:10:24: [AMXX] [1] crx_bestplayer.sma::client_infochanged (l
ine 135)
L 02/05/2021 - 13:10:24: [nVault] Invalid vault id: 0

L 02/05/2021 - 13:10:24: [AMXX] Displaying debug trace (plugin "crx_bestplayer.a
mxx", version "unknown")
L 02/05/2021 - 13:10:24: [AMXX] Run time error 10: native error (native "nvault_
get")
L 02/05/2021 - 13:10:24: [AMXX] [0] crx_bestplayer.sma::use_vault (line 400)
L 02/05/2021 - 13:10:24: [AMXX] [1] crx_bestplayer.sma::client_connect (line
114)
L 02/05/2021 - 13:10:24: Expected 0 parameters, got 3
L 02/05/2021 - 13:10:24: [AMXX] Displaying debug trace (plugin "crx_knife_models
.amxx", version "unknown")
L 02/05/2021 - 13:10:24: [AMXX] Run time error 10: native error (native "Execute
Forward")
L 02/05/2021 - 13:10:24: [AMXX] [0] crx_knife_models.sma::client_connect (lin
e 381)
Segmentation fault
Това става след като пусна плъгина на хакера с добавките от gadinkata
Търсих врага и го открих : това съм аз , трябва да се победя...
Изображение
WWW.CSMEGAGAMING.COM Изображение Изображение Skype : Sisi-1_1

Аватар
zolfeca
Извън линия
Администратор
Администратор
Мнения: 417
Регистриран на: 10 Окт 2016, 23:48
Се отблагодари: 24 пъти
Получена благодарност: 92 пъти

Помощ преработка Spec Bot Plugin

Мнение от zolfeca » 05 Фев 2021, 14:16

Добре, не ти ли прави впечатление, че ти вади грешки от други плъгини ? crx_bestplayer.sma & crx_knife_models.sma
Ако желаеш прикачи ги да видим за какво става въпрос.

Аватар
Siska
Извън линия
Потребител
Потребител
Мнения: 771
Регистриран на: 03 Дек 2019, 22:29
Местоположение: Bedrock
Се отблагодари: 157 пъти
Получена благодарност: 48 пъти
Обратна връзка:

Помощ преработка Spec Bot Plugin

Мнение от Siska » 05 Фев 2021, 15:14

zolfeca написа: 05 Фев 2021, 14:16 Добре, не ти ли прави впечатление, че ти вади грешки от други плъгини ? crx_bestplayer.sma & crx_knife_models.sma
Ако желаеш прикачи ги да видим за какво става въпрос.
Само когато пусна на хакера плъгина , ей тука малко по-нагоре гадинката е пуснал кога, само тогава излизат тези грешки от двата crx плъгина.
Когато спра бот спеца не излизат такива грешки, а когато спра двата въпросни плъгина и оставя само бот спеца, то сървъра пак не тръгва , но тогава няма грешки никакви , а пише просто - Segmentation fault...

Въпросните два плъгина ги има тук в сайта и моите не са променяни , но все пак ето кодовете :
crx_bestplayer

Код за потвърждение: Избери целия код

#include <amxmodx>
#include <hamsandwich>
#include <nvault>

//Comment if you're not using Counter-Strike.
#define USE_CSTRIKE

#define PLUGIN_VERSION "1.2.2"
#define MOTD_BEST "addons/amxmodx/configs/BestPlayer.txt"
#define MOTD_STATS "addons/amxmodx/configs/BestPlayerStats.txt"
#define MAX_MOTD_LENGTH 1536
#define MAX_HEADER_LENGTH 175
#define MAX_FORMULA_CYCLES 10

#define ARG_MAP "$map$"
#define ARG_NAME "$name$"
#define ARG_WINS "$wins$"
#define ARG_KILLS "$kills$"
#define ARG_KILLS_SB "$kills_sb$"
#define ARG_DEATHS "$deaths$"
#define ARG_DEATHS_SB "$deaths_sb$"
#define ARG_HEADSHOTS "$headshots$"
#define ARG_HITS "$hits$"
#define ARG_DAMAGE "$damage$"
#define ARG_KDRATIO "$kdratio$"
#define ARG_KDRATIO_SB "$kdratio_sb$"
#define ARG_HSRATIO "$hsratio$"

#if defined USE_CSTRIKE
	#include <cstrike>
	#define ARG_CTSCORE "$ctscore$"
	#define ARG_TSCORE "$tscore$"
	#define ARG_BEST_TEAM "$best_team$"
	#define get_user_deaths cs_get_user_deaths
	
new g_iTeamScore[3]
new const g_szTeams[][] = { "draw", "t", "ct" }
new const g_szTeamNames[][] = { "", "CT", "TERRORIST" }
#endif

#if defined client_disconnected
	#define client_disconnect client_disconnected
#endif

enum _:Cvars
{
	bpm_formula,
	bpm_min_players,
	bpm_motd_header,
	#if defined USE_CSTRIKE
	bpm_obey_team,
	#endif
	bpm_stats_header,
	bpm_save_type
}

enum _:PlayerData
{
	PDATA_INFO[35],
	PDATA_WINS,
	PDATA_KILLS,
	PDATA_KILLS_SB,
	PDATA_DEATHS,
	PDATA_DEATHS_SB,
	PDATA_HEADSHOTS,
	PDATA_HITS,
	Float:PDATA_DAMAGE,
	Float:PDATA_KDRATIO,
	Float:PDATA_KDRATIO_SB,
	Float:PDATA_HSRATIO
}

new g_eCvars[Cvars], g_iSaveType, g_iVault
new g_ePlayerData[33][PlayerData], g_szStats[MAX_MOTD_LENGTH], g_szMap[32]

public plugin_init()
{
	register_plugin("Best Player MOTD", PLUGIN_VERSION, "OciXCrom")
	register_cvar("CRXBestPlayer", PLUGIN_VERSION, FCVAR_SERVER|FCVAR_SPONLY|FCVAR_UNLOGGED)
	
	#if defined USE_CSTRIKE
	register_event("TeamScore", "OnTeamScore", "a")
	#endif
	
	RegisterHam(Ham_TakeDamage, "player", "OnTakeDamage", 1)
	register_event("DeathMsg", "OnPlayerKilled", "a")
	register_message(SVC_INTERMISSION, "OnIntermission")
	register_logevent("OnRestartRound", 2, "0=World triggered", "1&Restart_Round")
	register_clcmd("say /mystats", "Cmd_MyStats")
	register_clcmd("say_team /mystats", "Cmd_MyStats")
	
	g_eCvars[bpm_formula] = register_cvar("bpm_formula", "157")
	g_eCvars[bpm_min_players] = register_cvar("bpm_min_players", "6")
	g_eCvars[bpm_motd_header] = register_cvar("bpm_motd_header", "Best Player: $name$")
	#if defined USE_CSTRIKE
	g_eCvars[bpm_obey_team] = register_cvar("bpm_obey_team", "0")
	#endif
	g_eCvars[bpm_stats_header] = register_cvar("bpm_stats_header", "Player Stats: $name$")
	g_eCvars[bpm_save_type] = register_cvar("bpm_save_type", "0")
	get_mapname(g_szMap, charsmax(g_szMap))
	g_iVault = nvault_open("BestPlayer")
}

public plugin_cfg()
	g_iSaveType = get_pcvar_num(g_eCvars[bpm_save_type])
	
public plugin_end()
	nvault_close(g_iVault)

public client_connect(id)
{
	reset_player_stats(id)	
	get_user_saveinfo(id, g_ePlayerData[id][PDATA_INFO], charsmax(g_ePlayerData[][PDATA_INFO]))
	use_vault(id, 1, g_ePlayerData[id][PDATA_INFO])
}

public client_disconnect(id)
	use_vault(id, 0, g_ePlayerData[id][PDATA_INFO])

public client_infochanged(id)
{
	if(g_iSaveType > 0)
		return
		
	static szNewName[32], szOldName[32]
	get_user_info(id, "name", szNewName, charsmax(szNewName))
	get_user_name(id, szOldName, charsmax(szOldName))
	
	if(!equali(szNewName, szOldName))
	{
		strtolower(szNewName); strtolower(szOldName)
		copy(g_ePlayerData[id][PDATA_INFO], charsmax(g_ePlayerData[][PDATA_INFO]), szNewName)
		
		use_vault(id, 0, szOldName)
		use_vault(id, 1, szNewName)
	}
}

public Cmd_MyStats(id)
{
	if(!g_szStats[0])
		LoadFileForMe(MOTD_STATS, g_szStats, charsmax(g_szStats))
		
	static szMotd[MAX_MOTD_LENGTH]
	new szHeader[MAX_HEADER_LENGTH]
	copy(szMotd, charsmax(szMotd), g_szStats)
	get_pcvar_string(g_eCvars[bpm_stats_header], szHeader, charsmax(szHeader))
	calculate_stats(id)
	apply_replacements(id, szMotd, charsmax(szMotd))
	apply_replacements(id, szHeader, charsmax(szHeader))
	show_motd(id, szMotd, szHeader)
	return PLUGIN_HANDLED
}

public OnRestartRound()
{
	new iPlayers[32], iPnum
	get_players(iPlayers, iPnum)
	
	for(new i; i < iPnum; i++)
		reset_player_stats(iPlayers[i])
}

public OnTakeDamage(iVictim, iInflictor, iAttacker, Float:fDamage, iDamageBits)
{
	if(is_user_alive(iAttacker) && iAttacker != iVictim)
	{
		g_ePlayerData[iAttacker][PDATA_HITS]++
		g_ePlayerData[iAttacker][PDATA_DAMAGE] += fDamage
	}
}

public OnPlayerKilled()
{
	new iAttacker = read_data(1),
		iVictim = read_data(2)
		
	g_ePlayerData[iVictim][PDATA_DEATHS]++
		
	if(is_user_connected(iAttacker) && iAttacker != iVictim)
	{
		g_ePlayerData[iAttacker][PDATA_KILLS]++
		
		if(read_data(3))
			g_ePlayerData[iAttacker][PDATA_HEADSHOTS]++
	}
}

#if defined USE_CSTRIKE
public OnTeamScore()
{
	new szTeam[3], iScore = read_data(2)
	read_data(1, szTeam, charsmax(szTeam))
	g_iTeamScore[szTeam[0] == 'C' ? 2 : 1] = iScore
}
#endif

public OnIntermission()
{
	new iPlayers[32], iPnum
	
	#if defined USE_CSTRIKE
	new iTeam = get_pcvar_num(g_eCvars[bpm_obey_team])
	
	switch(iTeam)
	{
		case 0: get_players(iPlayers, iPnum)
		case 1, 2: get_players(iPlayers, iPnum, "e", g_szTeamNames[iTeam])
		case 3:
		{
			new iWinTeam = get_winning_team()
			
			switch(iWinTeam)
			{
				case 0: get_players(iPlayers, iPnum)
				case 1, 2: get_players(iPlayers, iPnum, "e", g_szTeamNames[iWinTeam])
			}
		}
	}
	#else
	get_players(iPlayers, iPnum)
	#endif
	
	if(!iPnum || iPnum < get_pcvar_num(g_eCvars[bpm_min_players]))
		return PLUGIN_CONTINUE
		
	new szFormula[MAX_FORMULA_CYCLES], iBest = iPlayers[0]
	get_pcvar_string(g_eCvars[bpm_formula], szFormula, charsmax(szFormula))
	
	new iLen = strlen(szFormula)
	
	for(new i, j, iPlayer, iScore, any:iBestScore; i < iPnum; i++)
	{
		iPlayer = iPlayers[i]
		calculate_stats(iPlayer)
		
		for(j = 0; j < iLen; j++)
		{
			iScore = get_score_by_formula(iPlayer, j, szFormula)
			iBestScore = get_score_by_formula(iBest, j, szFormula)
			
			if(iScore > iBestScore)
			{
				iBest = iPlayer
				break
			}
			else if(iScore == iBestScore)
			{
				if(j + 1 == iLen)
					break
					
				if(get_score_by_formula(iPlayer, j + 1, szFormula) > get_score_by_formula(iBest, j + 1, szFormula))
				{
					iPlayer = iBest
					break
				}
			}
		}
	}

	new bool:bNonZero
	
	for(new i; i < iLen; i++)
	{
		if(get_score_by_formula(iBest, i, szFormula) != 0)
		{
			bNonZero = true
			break
		}
	}
	
	if(!bNonZero)
		return PLUGIN_CONTINUE
	
	g_ePlayerData[iBest][PDATA_WINS]++
	
	new szMotd[MAX_MOTD_LENGTH], szHeader[MAX_HEADER_LENGTH]
	LoadFileForMe(MOTD_BEST, szMotd, charsmax(szMotd))
	get_pcvar_string(g_eCvars[bpm_motd_header], szHeader, charsmax(szHeader))
	apply_replacements(iBest, szMotd, charsmax(szMotd))
	apply_replacements(iBest, szHeader, charsmax(szHeader))
	show_motd(0, szMotd, szHeader)
	send_intermission()
	return PLUGIN_HANDLED
}

bool:has_argument(const szMessage[], const szArgument[])
	return contain(szMessage, szArgument) != -1

any:get_score_by_formula(const id, const iNum, const szFormula[])
{
	switch(szFormula[iNum])
	{
		case '0': return g_ePlayerData[id][PDATA_WINS]
		case '1': return g_ePlayerData[id][PDATA_KILLS]
		case '2': return g_ePlayerData[id][PDATA_KILLS_SB]
		case '3': return g_ePlayerData[id][PDATA_DEATHS] * -1
		case '4': return g_ePlayerData[id][PDATA_DEATHS_SB] * -1
		case '5': return g_ePlayerData[id][PDATA_HEADSHOTS]
		case '6': return g_ePlayerData[id][PDATA_HITS]
		case '7': return g_ePlayerData[id][PDATA_DAMAGE]
		case '8': return g_ePlayerData[id][PDATA_KDRATIO]
		case '9': return g_ePlayerData[id][PDATA_KDRATIO_SB]
		case 'a': return g_ePlayerData[id][PDATA_HSRATIO]
	}
	
	return 0
}

apply_replacements(const id, szMessage[], const iLen)
{	
	if(has_argument(szMessage, ARG_MAP))
		replace_all(szMessage, iLen, ARG_MAP, g_szMap)
		
	if(has_argument(szMessage, ARG_NAME))
	{
		static szBuffer[32]
		get_user_name(id, szBuffer, charsmax(szBuffer))
		replace_all(szMessage, iLen, ARG_NAME, szBuffer)
	}
	
	if(has_argument(szMessage, ARG_WINS))
		replace_num(szMessage, iLen, ARG_WINS, g_ePlayerData[id][PDATA_WINS])
		
	if(has_argument(szMessage, ARG_KILLS))
		replace_num(szMessage, iLen, ARG_KILLS, g_ePlayerData[id][PDATA_KILLS])
		
	if(has_argument(szMessage, ARG_KILLS_SB))
		replace_num(szMessage, iLen, ARG_KILLS_SB, g_ePlayerData[id][PDATA_KILLS_SB])
		
	if(has_argument(szMessage, ARG_DEATHS))
		replace_num(szMessage, iLen, ARG_DEATHS, g_ePlayerData[id][PDATA_DEATHS])
		
	if(has_argument(szMessage, ARG_DEATHS_SB))
		replace_num(szMessage, iLen, ARG_DEATHS_SB, g_ePlayerData[id][PDATA_DEATHS_SB])
		
	if(has_argument(szMessage, ARG_HEADSHOTS))
		replace_num(szMessage, iLen, ARG_HEADSHOTS, g_ePlayerData[id][PDATA_HEADSHOTS])
		
	if(has_argument(szMessage, ARG_HITS))
		replace_num(szMessage, iLen, ARG_HITS, g_ePlayerData[id][PDATA_HITS])
		
	if(has_argument(szMessage, ARG_DAMAGE))
		replace_num_f(szMessage, iLen, ARG_DAMAGE, g_ePlayerData[id][PDATA_DAMAGE])
		
	if(has_argument(szMessage, ARG_KDRATIO))
		replace_num_f(szMessage, iLen, ARG_KDRATIO, g_ePlayerData[id][PDATA_KDRATIO])
		
	if(has_argument(szMessage, ARG_KDRATIO_SB))
		replace_num_f(szMessage, iLen, ARG_KDRATIO_SB, g_ePlayerData[id][PDATA_KDRATIO_SB])
		
	if(has_argument(szMessage, ARG_HSRATIO))
		replace_num_f(szMessage, iLen, ARG_HSRATIO, g_ePlayerData[id][PDATA_HSRATIO])
		
	#if defined USE_CSTRIKE
	if(has_argument(szMessage, ARG_TSCORE))
		replace_num(szMessage, iLen, ARG_TSCORE, g_iTeamScore[1])
		
	if(has_argument(szMessage, ARG_CTSCORE))
		replace_num(szMessage, iLen, ARG_CTSCORE, g_iTeamScore[2])
		
	if(has_argument(szMessage, ARG_BEST_TEAM))
		replace_all(szMessage, iLen, ARG_BEST_TEAM, g_szTeams[get_winning_team()])
	#endif
}

#if defined USE_CSTRIKE
get_winning_team()
	return g_iTeamScore[1] == g_iTeamScore[2] ? 0 : g_iTeamScore[1] > g_iTeamScore[2] ? 1 : 2
#endif

reset_player_stats(const id)
{
	g_ePlayerData[id][PDATA_WINS] = 0
	g_ePlayerData[id][PDATA_KILLS] = 0
	g_ePlayerData[id][PDATA_KILLS_SB] = 0
	g_ePlayerData[id][PDATA_DEATHS] = 0
	g_ePlayerData[id][PDATA_DEATHS_SB] = 0
	g_ePlayerData[id][PDATA_HEADSHOTS] = 0
	g_ePlayerData[id][PDATA_HITS] = 0
	g_ePlayerData[id][PDATA_DAMAGE] = _:0.0
	g_ePlayerData[id][PDATA_KDRATIO] = _:0.0
	g_ePlayerData[id][PDATA_KDRATIO_SB] = _:0.0
	g_ePlayerData[id][PDATA_HSRATIO] = _:0.0
}

use_vault(const id, const iType, const szInfo[])
{
	if(!szInfo[0])
		return
	
	switch(iType)
	{
		case 0:
		{
			new szWins[10]
			num_to_str(g_ePlayerData[id][PDATA_WINS], szWins, charsmax(szWins))
			nvault_set(g_iVault, szInfo, szWins)
		}
		case 1:	g_ePlayerData[id][PDATA_WINS] = nvault_get(g_iVault, szInfo)
	}
}

get_user_saveinfo(const id, szInfo[], const iLen)
{
	switch(g_iSaveType)
	{
		case 0: { get_user_name(id, szInfo, iLen); strtolower(szInfo); }
		case 1: get_user_ip(id, szInfo, iLen, 1)
		case 2: get_user_authid(id, szInfo, iLen)
	}
}

calculate_stats(const id)
{
	g_ePlayerData[id][PDATA_KILLS_SB] = get_user_frags(id)
	g_ePlayerData[id][PDATA_DEATHS_SB] = get_user_deaths(id)
	g_ePlayerData[id][PDATA_KDRATIO] = g_ePlayerData[id][PDATA_DEATHS] ? (float(g_ePlayerData[id][PDATA_KILLS]) / float(g_ePlayerData[id][PDATA_DEATHS])) : float(g_ePlayerData[id][PDATA_KILLS])
	g_ePlayerData[id][PDATA_KDRATIO_SB] = g_ePlayerData[id][PDATA_DEATHS_SB] ? (float(g_ePlayerData[id][PDATA_KILLS_SB]) / float(g_ePlayerData[id][PDATA_DEATHS_SB])) : float(g_ePlayerData[id][PDATA_KILLS_SB])
	g_ePlayerData[id][PDATA_HSRATIO] = g_ePlayerData[id][PDATA_HEADSHOTS] ? (float(g_ePlayerData[id][PDATA_HEADSHOTS]) / float(g_ePlayerData[id][PDATA_KILLS])) : float(g_ePlayerData[id][PDATA_HEADSHOTS])
}

replace_num(szMessage[], const iLen, const szPlaceholder[], const iNum)
{
	static szBuffer[32]
	num_to_str(iNum, szBuffer, charsmax(szBuffer))
	replace_all(szMessage, iLen, szPlaceholder, szBuffer)
}

replace_num_f(szMessage[], const iLen, const szPlaceholder[], const Float:fNum)
{
	static szBuffer[32], i
	formatex(szBuffer, charsmax(szBuffer), "%.2f", fNum)
	i = strlen(szBuffer) - 1
	
	while(szBuffer[i] == '0' && szBuffer[i - 1] != '.')
		--i
		
	szBuffer[i + 1] = EOS
	replace_all(szMessage, iLen, szPlaceholder, szBuffer)
}

send_intermission()
{
	message_begin(MSG_ALL, SVC_FINALE)
	write_string("")
	message_end()
}

public plugin_natives()
{
	register_library("bestplayer")
	register_native("bpm_force_intermission", "_bpm_force_intermission")
}

public _bpm_force_intermission(iPlugin, iParams)
	OnIntermission()
crx_knife_models

Код за потвърждение: Избери целия код

#include <amxmodx>
#include <amxmisc>
#include <crxknives_const>
#include <cromchat>
#include <fakemeta>
#include <hamsandwich>
#include <nvault>

native crxranks_get_max_levels()
native crxranks_get_rank_by_level(level, buffer[], len)
native crxranks_get_user_level(id)
native crxranks_get_user_xp(id)

new const g_szNatives[][] =
{
	"crxranks_get_max_levels",
	"crxranks_get_rank_by_level",
	"crxranks_get_user_level",
	"crxranks_get_user_xp"
}

#if !defined m_pPlayer
const m_pPlayer = 41
#endif

#if !defined client_disconnected
	#define client_disconnected client_disconnect
#endif

new const PLUGIN_VERSION[] = "3.1.1"
const Float:DELAY_ON_CONNECT = 3.0

#if !defined MAX_AUTHID_LENGTH
const MAX_AUTHID_LENGTH = 35
#endif

#if !defined MAX_NAME_LENGTH
const MAX_NAME_LENGTH = 32
#endif

#if !defined MAX_PLAYERS
const MAX_PLAYERS = 32
#endif

enum
{
	SOUND_NONE = 0,
	SOUND_DEPLOY,
	SOUND_HIT,
	SOUND_HITWALL,
	SOUND_SLASH,
	SOUND_STAB
}

enum _:Knives
{
	NAME[MAX_NAME_LENGTH],
	V_MODEL[CRXKNIVES_MAX_SOUND_LENGTH],
	P_MODEL[CRXKNIVES_MAX_SOUND_LENGTH],
	DEPLOY_SOUND[CRXKNIVES_MAX_SOUND_LENGTH],
	HIT_SOUND[CRXKNIVES_MAX_SOUND_LENGTH],
	HITWALL_SOUND[CRXKNIVES_MAX_SOUND_LENGTH],
	SLASH_SOUND[CRXKNIVES_MAX_SOUND_LENGTH],
	STAB_SOUND[CRXKNIVES_MAX_SOUND_LENGTH],
	SELECT_SOUND[CRXKNIVES_MAX_SOUND_LENGTH],
	FLAG,
	LEVEL,
	XP,
	SELECT_MESSAGES_NUM,
	bool:SHOW_RANK,
	bool:HAS_CUSTOM_SOUND,
	Array:SELECT_MESSAGES,
	Trie:ATTRIBUTES
}

enum _:CvarsReg
{
	cvar_km_open_at_spawn,
	cvar_km_save_choice,
	cvar_km_only_dead,
	cvar_km_select_message,
	cvar_km_knife_only_skills,
	cvar_km_admin_bypass
}

enum _:Cvars
{
	km_open_at_spawn,
	km_save_choice,
	km_only_dead,
	km_select_message,
	km_knife_only_skills,
	km_admin_bypass
}

new Array:g_aKnives,
	bool:g_bFirstTime[MAX_PLAYERS + 1],
	bool:g_bRankSystem,
	bool:g_bGetLevel,
	bool:g_bGetXP,
	g_eCvars[Cvars],
	g_eCvarsReg[CvarsReg],
	g_eKnife[MAX_PLAYERS + 1][Knives],
	g_szAuth[MAX_PLAYERS + 1][MAX_AUTHID_LENGTH],
	g_iKnife[MAX_PLAYERS + 1],
	g_fwdKnifeUpdated,
	g_fwdAttemptChange,
	g_iMenuFlags,
	g_iKnivesNum,
	g_iCallback,
	g_iVault

public plugin_init()
{
	register_plugin("Knife Models", PLUGIN_VERSION, "OciXCrom")
	register_cvar("CRXKnifeModels", PLUGIN_VERSION, FCVAR_SERVER|FCVAR_SPONLY|FCVAR_UNLOGGED)

	if(!g_iKnivesNum)
	{
		set_fail_state("No knives found in the configuration file.")
	}

	register_dictionary("KnifeModels.txt")

	RegisterHam(Ham_Spawn, "player", "OnPlayerSpawn", 1)
	register_forward(FM_EmitSound,	"OnEmitSound")
	RegisterHam(Ham_Item_Deploy, "weapon_knife", "OnSelectKnife", 1)

	register_clcmd("say /knife",       "Cmd_Knife")
	register_clcmd("say_team /knife",  "Cmd_Knife")
	register_clcmd("crxknives_select", "Cmd_Select", _, "<knife id>")

	g_fwdKnifeUpdated  = CreateMultiForward("crxknives_knife_updated",  ET_IGNORE, FP_CELL, FP_CELL, FP_CELL)
	g_fwdAttemptChange = CreateMultiForward("crxknives_attempt_change", ET_STOP,   FP_CELL, FP_CELL)

	g_iCallback = menu_makecallback("CheckKnifeAccess")

	g_eCvarsReg[cvar_km_open_at_spawn]     = register_cvar("km_open_at_spawn",     "0")
	g_eCvarsReg[cvar_km_save_choice]       = register_cvar("km_save_choice",       "1")
	g_eCvarsReg[cvar_km_only_dead]         = register_cvar("km_only_dead",         "0")
	g_eCvarsReg[cvar_km_select_message]    = register_cvar("km_select_message",    "1")
	g_eCvarsReg[cvar_km_knife_only_skills] = register_cvar("km_knife_only_skills", "1")
	g_eCvarsReg[cvar_km_admin_bypass]      = register_cvar("km_admin_bypass",      "0")
}

public plugin_precache()
{
	if(LibraryExists("crxranks", LibType_Library))
	{
		g_bRankSystem = true
	}

	g_aKnives = ArrayCreate(Knives)
	ReadFile()
}

public plugin_cfg()
{
	g_eCvars[km_save_choice]       = get_pcvar_num(g_eCvarsReg[cvar_km_save_choice])
	g_eCvars[km_open_at_spawn]     = get_pcvar_num(g_eCvarsReg[cvar_km_open_at_spawn])
	g_eCvars[km_only_dead]         = get_pcvar_num(g_eCvarsReg[cvar_km_only_dead])
	g_eCvars[km_select_message]    = get_pcvar_num(g_eCvarsReg[cvar_km_select_message])
	g_eCvars[km_knife_only_skills] = get_pcvar_num(g_eCvarsReg[cvar_km_knife_only_skills])
	g_eCvars[km_admin_bypass]      = get_pcvar_num(g_eCvarsReg[cvar_km_admin_bypass])

	if(g_eCvars[km_save_choice])
	{
		g_iVault = nvault_open("KnifeModels")
	}
}

public plugin_end()
{
	for(new eKnife[Knives], i; i < g_iKnivesNum; i++)
	{
		ArrayGetArray(g_aKnives, i, eKnife)
		ArrayDestroy(eKnife[SELECT_MESSAGES])
		TrieDestroy(eKnife[ATTRIBUTES])
	}

	ArrayDestroy(g_aKnives)

	if(g_eCvars[km_save_choice])
	{
		nvault_close(g_iVault)
	}
}

ReadFile()
{
	new szFilename[256]
	get_configsdir(szFilename, charsmax(szFilename))
	add(szFilename, charsmax(szFilename), "/KnifeModels.ini")
	new iFilePointer = fopen(szFilename, "rt")

	if(iFilePointer)
	{
		new szData[160], szKey[32], szValue[128], szSound[128], iMaxLevels
		new eKnife[Knives], bool:bCustom

		if(g_bRankSystem)
		{
			iMaxLevels = crxranks_get_max_levels()
		}

		while(!feof(iFilePointer))
		{
			fgets(iFilePointer, szData, charsmax(szData))
			trim(szData)

			switch(szData[0])
			{
				case EOS, '#', ';': continue
				case '[':
				{
					if(szData[strlen(szData) - 1] == ']')
					{
						if(g_iKnivesNum)
						{
							push_knife(eKnife)
						}

						g_iKnivesNum++
						replace(szData, charsmax(szData), "[", "")
						replace(szData, charsmax(szData), "]", "")
						copy(eKnife[NAME], charsmax(eKnife[NAME]), szData)

						eKnife[V_MODEL][0] = EOS
						eKnife[P_MODEL][0] = EOS
						eKnife[DEPLOY_SOUND][0] = EOS
						eKnife[HIT_SOUND][0] = EOS
						eKnife[HITWALL_SOUND][0] = EOS
						eKnife[SLASH_SOUND][0] = EOS
						eKnife[STAB_SOUND][0] = EOS
						eKnife[SELECT_SOUND][0] = EOS
						eKnife[FLAG] = ADMIN_ALL
						eKnife[HAS_CUSTOM_SOUND] = false
						eKnife[SELECT_MESSAGES_NUM] = 0
						eKnife[SELECT_MESSAGES] = _:ArrayCreate(CRXKNIVES_MAX_MESSAGE_LENGTH)
						eKnife[ATTRIBUTES] = _:TrieCreate()

						if(g_bRankSystem)
						{
							eKnife[LEVEL] = 0
							eKnife[SHOW_RANK] = false
							eKnife[XP] = 0
						}

						static const ATTRIBUTE_NAME[] = "NAME"
						TrieSetString(eKnife[ATTRIBUTES], ATTRIBUTE_NAME, szData)
					}
					else continue
				}
				default:
				{
					strtok(szData, szKey, charsmax(szKey), szValue, charsmax(szValue), '=')
					trim(szKey); trim(szValue)
					bCustom = true

					TrieSetString(eKnife[ATTRIBUTES], szKey, szValue)

					if(equal(szKey, "FLAG"))
					{
						eKnife[FLAG] = read_flags(szValue)
						g_iMenuFlags |= eKnife[FLAG]
					}
					else if(equal(szKey, "LEVEL") && g_bRankSystem)
					{
						eKnife[LEVEL] = clamp(str_to_num(szValue), 0, iMaxLevels)

						if(!g_bGetLevel)
						{
							g_bGetLevel = true
						}
					}
					else if(equal(szKey, "SHOW_RANK") && g_bRankSystem)
					{
						eKnife[SHOW_RANK] = _:clamp(str_to_num(szValue), false, true)
					}
					else if(equal(szKey, "XP") && g_bRankSystem)
					{
						eKnife[XP] = _:clamp(str_to_num(szValue), 0)

						if(!g_bGetXP)
						{
							g_bGetXP = true
						}
					}
					else if(equal(szKey, "V_MODEL"))
					{
						copy(eKnife[V_MODEL], charsmax(eKnife[V_MODEL]), szValue)
					}
					else if(equal(szKey, "P_MODEL"))
					{
						copy(eKnife[P_MODEL], charsmax(eKnife[P_MODEL]), szValue)
					}
					else if(equal(szKey, "DEPLOY_SOUND"))
					{
						copy(eKnife[DEPLOY_SOUND], charsmax(eKnife[DEPLOY_SOUND]), szValue)
					}
					else if(equal(szKey, "HIT_SOUND"))
					{
						copy(eKnife[HIT_SOUND], charsmax(eKnife[HIT_SOUND]), szValue)
					}
					else if(equal(szKey, "HITWALL_SOUND"))
					{
						copy(eKnife[HITWALL_SOUND], charsmax(eKnife[HITWALL_SOUND]), szValue)
					}
					else if(equal(szKey, "SLASH_SOUND"))
					{
						copy(eKnife[SLASH_SOUND], charsmax(eKnife[SLASH_SOUND]), szValue)
					}
					else if(equal(szKey, "STAB_SOUND"))
					{
						copy(eKnife[STAB_SOUND], charsmax(eKnife[STAB_SOUND]), szValue)
					}
					else if(equal(szKey, "SELECT_SOUND"))
					{
						bCustom = false
						copy(eKnife[SELECT_SOUND], charsmax(eKnife[SELECT_SOUND]), szValue)
					}
					else if(equal(szKey, "SELECT_MESSAGE"))
					{
						ArrayPushString(eKnife[SELECT_MESSAGES], szValue)
						eKnife[SELECT_MESSAGES_NUM]++
					}
					else continue

					static const szModelArg[] = "_MODEL"
					static const szSoundArg[] = "_SOUND"

					if(contain(szKey, szModelArg) != -1)
					{
						if(!file_exists(szValue))
						{
							log_amx("ERROR: model ^"%s^" not found!", szValue)
						}
						else
						{
							precache_model(szValue)
						}
					}
					else if(contain(szKey, szSoundArg) != -1)
					{
						formatex(szSound, charsmax(szSound), "sound/%s", szValue)

						if(!file_exists(szSound))
						{
							log_amx("ERROR: sound ^"%s^" not found!", szSound)
						}
						else
						{
							precache_sound(szValue)
						}

						if(bCustom)
						{
							eKnife[HAS_CUSTOM_SOUND] = true
						}
					}
				}
			}
		}

		if(g_iKnivesNum)
		{
			push_knife(eKnife)
		}

		fclose(iFilePointer)
	}
}

public client_connect(id)
{
	g_bFirstTime[id] = true
	ArrayGetArray(g_aKnives, 0, g_eKnife[id])
	g_iKnife[id] = 0

	new iReturn
	ExecuteForward(g_fwdKnifeUpdated, iReturn, id, g_iKnife[id], true)

	if(g_eCvars[km_save_choice])
	{
		get_user_authid(id, g_szAuth[id], charsmax(g_szAuth[]))
		set_task(DELAY_ON_CONNECT, "load_data", id)
	}
}

public client_disconnected(id)
{
	if(g_eCvars[km_save_choice])
	{
		use_vault(id, true)
	}
}

public OnEmitSound(id, iChannel, const szSample[])
{
	if(!is_user_connected(id) || !g_eKnife[id][HAS_CUSTOM_SOUND] || !is_knife_sound(szSample))
	{
		return FMRES_IGNORED
	}

	switch(detect_knife_sound(szSample))
	{
		case SOUND_DEPLOY: 		if(g_eKnife[id][DEPLOY_SOUND][0]) 		{ play_knife_sound(id, g_eKnife[id][DEPLOY_SOUND][0]);      return FMRES_SUPERCEDE; }
		case SOUND_HIT: 		if(g_eKnife[id][HIT_SOUND][0]) 			{ play_knife_sound(id, g_eKnife[id][HIT_SOUND][0]);         return FMRES_SUPERCEDE; }
		case SOUND_HITWALL:		if(g_eKnife[id][HITWALL_SOUND][0]) 		{ play_knife_sound(id, g_eKnife[id][HITWALL_SOUND][0]);     return FMRES_SUPERCEDE; }
		case SOUND_SLASH: 		if(g_eKnife[id][SLASH_SOUND][0]) 		{ play_knife_sound(id, g_eKnife[id][SLASH_SOUND][0]);       return FMRES_SUPERCEDE; }
		case SOUND_STAB: 		if(g_eKnife[id][STAB_SOUND][0]) 		{ play_knife_sound(id, g_eKnife[id][STAB_SOUND][0]);        return FMRES_SUPERCEDE; }
	}

	return FMRES_IGNORED
}

public Cmd_Knife(id)
{
	if(g_eCvars[km_only_dead] && is_user_alive(id))
	{
		CC_SendMessage(id, "%L %L", id, "KM_CHAT_PREFIX", id, "KM_ONLY_DEAD")
		return PLUGIN_HANDLED
	}

	static eKnife[Knives]
	new szTitle[128], szItem[128], iLevel, iXP
	formatex(szTitle, charsmax(szTitle), "%L", id, "KM_MENU_TITLE")

	if(g_bGetLevel)
	{
		iLevel = crxranks_get_user_level(id)
	}

	if(g_bGetXP)
	{
		iXP = crxranks_get_user_xp(id)
	}

	new iMenu = menu_create(szTitle, "MenuHandler")
	menu_setprop(iMenu, MPROP_PERPAGE, 5)

	for(new iFlags = get_user_flags(id), i; i < g_iKnivesNum; i++)
	{
		ArrayGetArray(g_aKnives, i, eKnife)
		copy(szItem, charsmax(szItem), eKnife[NAME])

		if(g_bRankSystem)
		{
			if(eKnife[LEVEL] && iLevel < eKnife[LEVEL])
			{
				if(eKnife[SHOW_RANK])
				{
					static szRank[32]
					crxranks_get_rank_by_level(eKnife[LEVEL], szRank, charsmax(szRank))
					format(szItem, charsmax(szItem), "%s %L", szItem, id, "KM_MENU_RANK", szRank)
				}
				else
				{
					format(szItem, charsmax(szItem), "%s %L", szItem, id, "KM_MENU_LEVEL", eKnife[LEVEL])
				}
			}

			if(eKnife[XP] && iXP < eKnife[XP])
			{
				format(szItem, charsmax(szItem), "%s %L", szItem, id, "KM_MENU_XP", eKnife[XP])
			}
		}

		if(eKnife[FLAG] != ADMIN_ALL && !(iFlags & eKnife[FLAG]))
		{
			format(szItem, charsmax(szItem), "%s %L", szItem, id, "KM_MENU_VIP_ONLY")
		}

		if(g_iKnife[id] == i)
		{
			format(szItem, charsmax(szItem), "%s %L", szItem, id, "KM_MENU_SELECTED")
		}

		menu_additem(iMenu, szItem, eKnife[NAME], eKnife[FLAG], g_iCallback)
	}

	if(menu_pages(iMenu) > 1)
	{
		formatex(szItem, charsmax(szItem), "%s%L", szTitle, id, "KM_MENU_TITLE_PAGE")
		menu_setprop(iMenu, MPROP_TITLE, szItem)
	}

	menu_display(id, iMenu)
	return PLUGIN_HANDLED
}

public Cmd_Select(id, iLevel, iCid)
{
	if(!cmd_access(id, iLevel, iCid, 2))
	{
		return PLUGIN_HANDLED
	}

	if(g_eCvars[km_only_dead] && is_user_alive(id))
	{
		CC_SendMessage(id, "%L %L", id, "KM_CHAT_PREFIX", id, "KM_ONLY_DEAD")
		return PLUGIN_HANDLED
	}

	new szKnife[4]
	read_argv(1, szKnife, charsmax(szKnife))

	new iKnife = str_to_num(szKnife)

	if(!is_knife_valid(iKnife))
	{
		console_print(id, "%l", "KM_INVALID_KNIFE", g_iKnivesNum - 1)
		return PLUGIN_HANDLED
	}

	if(!has_knife_access(id, iKnife))
	{
		console_print(id, "%l", "KM_NO_ACCESS")
		return PLUGIN_HANDLED
	}

	select_knife(id, iKnife)
	return PLUGIN_HANDLED
}

public MenuHandler(id, iMenu, iItem)
{
	if(g_eCvars[km_only_dead] && is_user_alive(id))
	{
		CC_SendMessage(id, "%L %L", id, "KM_CHAT_PREFIX", id, "KM_ONLY_DEAD")
		goto @MENU_DESTROY
	}

	if(!is_user_connected(id))
	{
		goto @MENU_DESTROY
	}

	if(iItem != MENU_EXIT)
	{
		select_knife(id, iItem)
	}

	@MENU_DESTROY:
	menu_destroy(iMenu)
	return PLUGIN_HANDLED
}

select_knife(id, iKnife)
{
	new iReturn
	ExecuteForward(g_fwdAttemptChange, iReturn, id, iKnife)

	if(iReturn == PLUGIN_HANDLED)
	{
		return
	}

	g_iKnife[id] = iKnife
	ArrayGetArray(g_aKnives, iKnife, g_eKnife[id])
	ExecuteForward(g_fwdKnifeUpdated, iReturn, id, iKnife, false)

	if(is_user_alive(id) && get_user_weapon(id) == CSW_KNIFE)
	{
		refresh_knife_model(id)
	}

	if(g_eCvars[km_select_message])
	{
		CC_SendMessage(id, "%L %L", id, "KM_CHAT_PREFIX", id, "KM_CHAT_SELECTED", g_eKnife[id][NAME])
	}

	if(g_eKnife[id][SELECT_MESSAGES_NUM])
	{
		for(new i; i < g_eKnife[id][SELECT_MESSAGES_NUM]; i++)
		{
			CC_SendMessage(id, "%a", ArrayGetStringHandle(g_eKnife[id][SELECT_MESSAGES], i))
		}
	}

	if(g_eKnife[id][SELECT_SOUND][0])
	{
		play_knife_sound(id, g_eKnife[id][SELECT_SOUND])
	}
}

public load_data(id)
{
	if(is_user_connected(id))
	{
		use_vault(id, false)
	}
}

public CheckKnifeAccess(id, iMenu, iItem)
{
	return ((g_iKnife[id] == iItem) || !has_knife_access(id, iItem)) ? ITEM_DISABLED : ITEM_ENABLED
}

public OnPlayerSpawn(id)
{
	if(is_user_alive(id) && g_eCvars[km_open_at_spawn] && !g_iKnife[id] && g_bFirstTime[id] && (g_iMenuFlags & ADMIN_USER || get_user_flags(id) & g_iMenuFlags))
	{
		g_bFirstTime[id] = false
		Cmd_Knife(id)
	}
}

public OnSelectKnife(iEnt)
{
	new id = get_pdata_cbase(iEnt, m_pPlayer, 4)

	if(is_user_connected(id))
	{
		refresh_knife_model(id)
	}
}

refresh_knife_model(const id)
{
	set_pev(id, pev_viewmodel2, g_eKnife[id][V_MODEL])
	set_pev(id, pev_weaponmodel2, g_eKnife[id][P_MODEL])
}

push_knife(eKnife[Knives])
{
	if(!eKnife[V_MODEL][0])
	{
		copy(eKnife[V_MODEL], charsmax(eKnife[V_MODEL]), CRXKNIVES_DEFAULT_V)
	}

	if(!eKnife[P_MODEL][0])
	{
		copy(eKnife[P_MODEL], charsmax(eKnife[P_MODEL]), CRXKNIVES_DEFAULT_P)
	}

	if(!eKnife[FLAG])
	{
		g_iMenuFlags |= ADMIN_USER
	}

	ArrayPushArray(g_aKnives, eKnife)
}

bool:has_knife_access(const id, const iKnife)
{
	static eKnife[Knives]
	ArrayGetArray(g_aKnives, iKnife, eKnife)

	if(eKnife[FLAG] != ADMIN_ALL)
	{
		if(get_user_flags(id) & eKnife[FLAG])
		{
			if(g_eCvars[km_admin_bypass])
			{
				return true
			}
		}
		else
		{
			return false
		}
	}

	if(g_bRankSystem)
	{
		if(eKnife[LEVEL] && crxranks_get_user_level(id) < eKnife[LEVEL])
		{
			return false
		}

		if(eKnife[XP] && crxranks_get_user_xp(id) < eKnife[XP])
		{
			return false
		}
	}

	return true
}

bool:is_knife_sound(const szSample[])
{
	return bool:equal(szSample[8], "kni", 3)
}

detect_knife_sound(const szSample[])
{
	static iSound
	iSound = SOUND_NONE

	if(equal(szSample, "weapons/knife_deploy1.wav"))
	{
		iSound = SOUND_DEPLOY
	}
	else if(equal(szSample[14], "hit", 3))
	{
		iSound = szSample[17] == 'w' ? SOUND_HITWALL : SOUND_HIT
	}
	else if(equal(szSample[14], "sla", 3))
	{
		iSound = SOUND_SLASH
	}
	else if(equal(szSample[14], "sta", 3))
	{
		iSound = SOUND_STAB
	}

	return iSound
}

use_vault(const id, const bool:bSave)
{
	if(bSave)
	{
		new szData[4]
		num_to_str(g_iKnife[id], szData, charsmax(szData))
		nvault_set(g_iVault, g_szAuth[id], szData)
	}
	else
	{
		new iKnife
		iKnife = nvault_get(g_iVault, g_szAuth[id])

		if(!is_knife_valid(iKnife))
		{
			iKnife = 0
		}
		else if(has_knife_access(id, iKnife))
		{
			g_iKnife[id] = iKnife

			new iReturn
			ArrayGetArray(g_aKnives, iKnife, g_eKnife[id])
			ExecuteForward(g_fwdKnifeUpdated, iReturn, id, iKnife, false)

			if(is_user_alive(id) && get_user_weapon(id) == CSW_KNIFE)
			{
				refresh_knife_model(id)
			}
		}
	}
}

play_knife_sound(const id, const szSound[])
{
	engfunc(EngFunc_EmitSound, id, CHAN_AUTO, szSound, 1.0, ATTN_NORM, 0, PITCH_NORM)
}

bool:is_knife_valid(const iKnife)
{
	return 0 <= iKnife < g_iKnivesNum
}

public plugin_natives()
{
	register_library("crxknives")
	register_native("crxknives_can_use_skill",       "_crxknives_can_use_skill")
	register_native("crxknives_get_attribute_int",   "_crxknives_get_attribute_int")
	register_native("crxknives_get_attribute_float", "_crxknives_get_attribute_float")
	register_native("crxknives_get_attribute_str",   "_crxknives_get_attribute_str")
	register_native("crxknives_get_knives_num",      "_crxknives_get_knives_num")
	register_native("crxknives_get_user_knife",      "_crxknives_get_user_knife")
	register_native("crxknives_has_knife_access",    "_crxknives_has_knife_access")
	register_native("crxknives_is_knife_valid",      "_crxknives_is_knife_valid")
	set_native_filter("native_filter")
}

public native_filter(const szNative[], id, iTrap)
{
	if(!iTrap)
	{
		static i

		for(i = 0; i < sizeof(g_szNatives); i++)
		{
			if(equal(szNative, g_szNatives[i]))
			{
				return PLUGIN_HANDLED
			}
		}
	}

	return PLUGIN_CONTINUE
}

public bool:_crxknives_can_use_skill(iPlugin, iParams)
{
	return !g_eCvars[km_knife_only_skills] || (get_user_weapon(get_param(1)) == CSW_KNIFE)
}

public bool:_crxknives_get_attribute_int(iPlugin, iParams)
{
	static szAttribute[MAX_NAME_LENGTH], szValue[CRXKNIVES_MAX_ATTRIBUTE_LENGTH], id
	get_string(2, szAttribute, charsmax(szAttribute))
	id = get_param(1)

	if(!get_param(4))
	{
		if(!is_knife_valid(id))
		{
			return false
		}

		static eKnife[Knives]
		ArrayGetArray(g_aKnives, id, eKnife)

		if(!TrieKeyExists(eKnife[ATTRIBUTES], szAttribute))
		{
			return false
		}

		TrieGetString(eKnife[ATTRIBUTES], szAttribute, szValue, charsmax(szValue))
		goto @SET_ATTRIBUTE
	}

	if(!TrieKeyExists(g_eKnife[id][ATTRIBUTES], szAttribute))
	{
		return false
	}

	TrieGetString(g_eKnife[id][ATTRIBUTES], szAttribute, szValue, charsmax(szValue))

	@SET_ATTRIBUTE:
	set_param_byref(3, str_to_num(szValue))
	return true
}

public bool:_crxknives_get_attribute_float(iPlugin, iParams)
{
	static szAttribute[MAX_NAME_LENGTH], szValue[CRXKNIVES_MAX_ATTRIBUTE_LENGTH], id
	get_string(2, szAttribute, charsmax(szAttribute))
	id = get_param(1)

	if(!get_param(4))
	{
		if(!is_knife_valid(id))
		{
			return false
		}

		static eKnife[Knives]
		ArrayGetArray(g_aKnives, id, eKnife)

		if(!TrieKeyExists(eKnife[ATTRIBUTES], szAttribute))
		{
			return false
		}

		TrieGetString(eKnife[ATTRIBUTES], szAttribute, szValue, charsmax(szValue))
		goto @SET_ATTRIBUTE
	}

	if(!TrieKeyExists(g_eKnife[id][ATTRIBUTES], szAttribute))
	{
		return false
	}

	TrieGetString(g_eKnife[id][ATTRIBUTES], szAttribute, szValue, charsmax(szValue))

	@SET_ATTRIBUTE:
	set_float_byref(3, str_to_float(szValue))
	return true
}

public bool:_crxknives_get_attribute_str(iPlugin, iParams)
{
	static szAttribute[MAX_NAME_LENGTH], szValue[CRXKNIVES_MAX_ATTRIBUTE_LENGTH], id
	get_string(2, szAttribute, charsmax(szAttribute))
	id = get_param(1)

	if(!get_param(5))
	{
		if(!is_knife_valid(id))
		{
			return false
		}

		static eKnife[Knives]
		ArrayGetArray(g_aKnives, id, eKnife)

		if(!TrieKeyExists(eKnife[ATTRIBUTES], szAttribute))
		{
			return false
		}

		TrieGetString(eKnife[ATTRIBUTES], szAttribute, szValue, charsmax(szValue))
		goto @SET_ATTRIBUTE
	}

	if(!TrieKeyExists(g_eKnife[id][ATTRIBUTES], szAttribute))
	{
		return false
	}

	TrieGetString(g_eKnife[id][ATTRIBUTES], szAttribute, szValue, charsmax(szValue))

	@SET_ATTRIBUTE:
	set_string(3, szValue, get_param(4))
	return true
}

public _crxknives_get_knives_num(iPlugin, iParams)
{
	return g_iKnivesNum
}

public _crxknives_get_user_knife(iPlugin, iParams)
{
	return g_iKnife[get_param(1)]
}

public bool:_crxknives_has_knife_access(iPlugin, iParams)
{
	return has_knife_access(get_param(1), get_param(2))
}

public bool:_crxknives_is_knife_valid(iPlugin, iParams)
{
	return is_knife_valid(get_param(1))
}
knife models всъщност има промяна като вместо по 7 на страница от менюто излизат по 5 оръжия...

Това пък е другия бот спец , който се опитвам да пусна. Ето кода :

Код за потвърждение: Избери целия код

#include amxmodx
#include fakemeta

#define AUTHOR "$Alvad0r"
#define VERSION "1.0.0"
#define PLUGIN_NAME "BotKikck Server Full"

#define NUMAR_DE_BOTI 2

new g_Query[256];
new botz;

public plugin_init()
{
    register_plugin(PLUGIN_NAME, VERSION, AUTHOR);
    set_task( 5.0, "TaskManageBots", .flags="b" );
    botz = 0;
}

new g_Bot[33], g_BotsCount;

public TaskManageBots(){
    static PlayersNum; PlayersNum  = get_playersnum( 1 );
    if( PlayersNum < get_maxplayers() - 1 && g_BotsCount < 3 )
    {
        CreateBot();
    }
    else if(PlayersNum > get_maxplayers() - 1 && g_BotsCount )
    {
        RemoveBot();
    }
}
new const g_Names[][]=
{
    "www.csmegagaming.com",
    "IP: cl.csmegagaming.com:27017"
    
};

public client_disconnect(i)
{
   if( g_Bot[ i ] ) {
      g_Bot[ i ] = 0, g_BotsCount -- ; botz -= 1;
   }
}

RemoveBot(){
   static i;
   for( i = 1; i <= get_maxplayers(); i++ ) {
      if(g_Bot[ i ]) 
      {
        server_cmd( "kick #%d", get_user_userid( i ) );
        botz -= 1;
        break;
      }}}

CreateBot(){
   static Bot;
   formatex( g_Query, 255, "%s", g_Names[botz] );
   botz += 1;
   Bot = engfunc( EngFunc_CreateFakeClient, g_Query );
   if( Bot > 0 &&pev_valid(Bot)) {
      dllfunc(MetaFunc_CallGameEntity,"player",Bot);
      set_pev(Bot,pev_flags,FL_FAKECLIENT);
      set_pev(Bot, pev_model, "");
      set_pev(Bot, pev_viewmodel2, "");
      set_pev(Bot, pev_modelindex, 0);
      set_pev(Bot, pev_renderfx, kRenderFxNone);
      set_pev(Bot, pev_rendermode, kRenderTransAlpha);
      set_pev(Bot, pev_renderamt, 0.0);
      set_pdata_int(Bot,114,0);
      message_begin(MSG_ALL,get_user_msgid("TeamInfo"));
      write_byte(Bot);
      write_string("UNASSIGNED");
      message_end();
      g_Bot[Bot]=1;
      g_BotsCount++;
   }
}  
И ето с дебъг какво показва този плъгин :
L 02/05/2021 - 15:32:55: [AMXX] Run time error 4: index out of bounds
L 02/05/2021 - 15:32:55: [AMXX] [0] bot_spec.sma::CreateBot (line 59)
L 02/05/2021 - 15:32:55: [AMXX] [1] bot_spec.sma::TaskManageBots (line 26)
Търсих врага и го открих : това съм аз , трябва да се победя...
Изображение
WWW.CSMEGAGAMING.COM Изображение Изображение Skype : Sisi-1_1

Аватар
Siska
Извън линия
Потребител
Потребител
Мнения: 771
Регистриран на: 03 Дек 2019, 22:29
Местоположение: Bedrock
Се отблагодари: 157 пъти
Получена благодарност: 48 пъти
Обратна връзка:

Помощ преработка Spec Bot Plugin

Мнение от Siska » 23 Мар 2021, 15:09

Тази тема също е излишна. Няма кой да се занимава с този бот спец , а и аз вече имам горе-долу работещ такъв.
Може да заключвате...
Търсих врага и го открих : това съм аз , трябва да се победя...
Изображение
WWW.CSMEGAGAMING.COM Изображение Изображение Skype : Sisi-1_1

Заключено
  • Подобни теми
    Отговори
    Преглеждания
     Последно мнение

Обратно към “Поддръжка / Помощ”

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 8 госта