#include <amxmodx>
#include <amxmisc>
#include <fun>
#include <fakemeta>
#include <hamsandwich>
#include <sqlx>
new Handle:g_hSQLTuple
new bool:g_bDueling[32], g_iOpponent[32], g_iHealth[32], bool:g_bAntiFlood[32]
new g_iTotalKills[32], g_iTotalDeaths[32], g_iDuelWins[32], g_iDuelLosses[32]
new g_pEnabled, g_pMsgInterval
new g_mDuelMenu[32]
public plugin_init()
{
register_plugin("Duel System", "1.0", "Spunky")
RegisterHam(Ham_TakeDamage, "player", "fnTakeDamage", 0)
RegisterHam(Ham_Killed, "player", "fnKilled", 1)
register_concmd("esf_duel", "concmd_duel", ADMIN_ALL, "<name>")
register_concmd("esf_stats", "concmd_stats", ADMIN_ALL, "")
register_clcmd("say /duel", "cmd_duel")
register_clcmd("say /cancel", "cmd_cancel")
register_clcmd("say /author", "cmd_author")
g_pEnabled = register_cvar("esf_duel_enable", "1")
g_pMsgInterval = register_cvar("esf_duel_msg", "90")
if (get_pcvar_num(g_pMsgInterval))
set_task(get_pcvar_float(g_pMsgInterval), "fnMsgDisplay", random(1337), _, _, "b")
fnSQLInit()
}
public fnMsgDisplay()
{
new iPlayers[32], iPlayerNum
get_players(iPlayers, iPlayerNum)
for (new i = 0; i <= iPlayerNum; i++)
{
if (is_user_alive(iPlayers[i]) && !is_user_bot(iPlayers[i]))
{
client_print(iPlayers[i], print_chat, "[DM] This server is running Spunky's Duel System.")
client_print(iPlayers[i], print_chat, "[DM] Use 'amx_help' for a list of duel commands.")
}
}
}
public plugin_end()
if (g_hSQLTuple)
SQL_FreeHandle(g_hSQLTuple)
public fnSQLInit()
{
g_hSQLTuple = SQL_MakeStdTuple()
SQL_ThreadQuery(g_hSQLTuple, "fnCreateSQLTable", "CREATE TABLE IF NOT EXISTS esf_duel (SteamID VARCHAR(32), TotalKills INT(6), TotalDeaths INT(6), DuelWins INT(6), DuelLosses INT(6), UNIQUE (SteamID))")
}
public fnCreateSQLTable(FailState, Handle:hQuery, szError[], iErrorCode)
{
if (iErrorCode)
set_fail_state(szError)
return PLUGIN_CONTINUE
}
public client_putinserver(id)
{
new szID[20]
get_user_authid(id, szID, 19)
new iData[1]
iData[0] = id
new szQuery[256]
formatex(szQuery, 255, "SELECT * FROM esf_duel WHERE SteamID = '%s'", szID)
SQL_ThreadQuery(g_hSQLTuple, "fnLoadData", szQuery, iData, 1)
}
public fnLoadData(FailState, Handle:hQuery, szError[], iErrorCode, iData[], iDataSize)
{
if (iErrorCode)
set_fail_state(szError)
new const id = iData[0], iIndex = id - 1
if (SQL_NumResults(hQuery) > 0)
{
g_iTotalKills[iIndex] = SQL_ReadResult(hQuery, 1)
g_iTotalDeaths[iIndex] = SQL_ReadResult(hQuery, 2)
g_iDuelWins[iIndex] = SQL_ReadResult(hQuery, 3)
g_iDuelLosses[iIndex] = SQL_ReadResult(hQuery, 4)
}
else
{
new szID[20]
get_user_authid(id, szID, 19)
new szQuery[256]
formatex(szQuery, 255, "INSERT INTO esf_duel VALUES ('%s', 0, 0, 0, 0)", szID)
SQL_ThreadQuery(g_hSQLTuple, "fnCreateData", szQuery)
}
return PLUGIN_CONTINUE
}
public fnCreateData(FailState, Handle:hQuery, szError[], iErrorCode)
{
if (iErrorCode)
set_fail_state(szError)
return PLUGIN_CONTINUE
}
public client_disconnect(id)
{
new const iIndex = id - 1
g_bDueling[iIndex] = false
if (g_iOpponent[iIndex])
{
new const iTargetIndex = g_iOpponent[iIndex] - 1
g_iOpponent[iIndex] = 0
g_iOpponent[iTargetIndex] = 0
g_bDueling[iTargetIndex] = false
}
g_iTotalKills[iIndex] = 0
g_iTotalDeaths[iIndex] = 0
g_iDuelWins[iIndex] = 0
g_iDuelLosses[iIndex] = 0
g_iHealth[iIndex] = 0
g_mDuelMenu[iIndex] = 0
}
public fnTakeDamage(id, inflictor_id, attacker_id, Float:damage, damagebits)
{
if (!get_pcvar_num(g_pEnabled))
return HAM_IGNORED
new const iIndex = id - 1, iAttackerIndex = attacker_id - 1
if (!g_bDueling[iIndex] && g_bDueling[iAttackerIndex])
{
client_print(attacker_id, print_chat, "[DM] Your attacks to no damage to non-dueling players.")
return HAM_SUPERCEDE
}
if (g_bDueling[iIndex])
{
if (id == attacker_id)
return HAM_IGNORED
if (attacker_id != g_iOpponent[iIndex])
{
if (!g_bAntiFlood[iIndex])
{
client_print(attacker_id, print_chat, "[DM] Your attacks do no damage to dueling players.")
g_bAntiFlood[iAttackerIndex] = true
new iData[1]
iData[0] = attacker_id
set_task(15.0, "fnAntiFloodUpdate", random(1337), iData, 1)
}
return HAM_SUPERCEDE
}
}
return HAM_IGNORED
}
public fnAntiFloodUpdate(iData[])
{
new const iIndex = iData[0] - 1
g_bAntiFlood[iIndex] = false
}
public fnKilled(id, iid, aid, iShouldGib)
{
if (!get_pcvar_num(g_pEnabled))
return HAM_IGNORED
new const iIndex = id - 1
if (g_bDueling[iIndex])
{
new const iTargetIndex = g_iOpponent[iIndex] - 1
set_user_rendering(id, kRenderFxNone, 0, 0, 0, kRenderNormal, 0)
set_user_rendering(g_iOpponent[iIndex], kRenderFxNone, 0, 0, 0, kRenderNormal, 0)
client_print(id, print_chat, "[DM] You lost the duel!")
client_print(g_iOpponent[iIndex], print_chat, "[DM] You won the duel!")
set_user_health(g_iOpponent[iIndex], g_iHealth[iTargetIndex])
client_print(g_iOpponent[iIndex], print_chat, "[DM] Your health has been restored to its original value.")
g_iTotalDeaths[iIndex]++
g_iDuelLosses[iIndex]++
fnSave(id)
g_iTotalKills[iTargetIndex]++
g_iDuelWins[iTargetIndex]++
fnSave(g_iOpponent[iIndex])
g_bDueling[iIndex] = false
g_bDueling[iTargetIndex] = false
g_iOpponent[iIndex] = 0
g_iOpponent[iTargetIndex] = 0
}
else
{
new const iTargetIndex = aid - 1
g_iTotalDeaths[iIndex]++
fnSave(id)
g_iTotalKills[iTargetIndex]++
fnSave(aid)
}
return HAM_IGNORED
}
public fnSave(id)
{
new const iIndex = id - 1
new szID[20]
get_user_authid(id, szID, 19)
new szQuery[256]
formatex(szQuery, 255, "UPDATE esf_duel SET TotalKills = %d, TotalDeaths = %d, DuelWins = %d, DuelLosses = %d WHERE SteamID = '%s'", g_iTotalKills[iIndex], g_iTotalDeaths[iIndex], g_iDuelWins[iIndex], g_iDuelLosses[iIndex], szID)
SQL_ThreadQuery(g_hSQLTuple, "fnSaveData", szQuery)
}
public fnSaveData(FailState, Handle:hQuery, szError[], iErrorCode)
{
if (iErrorCode)
set_fail_state(szError)
return PLUGIN_CONTINUE
}
public concmd_duel(id)
{
if (!get_pcvar_num(g_pEnabled))
{
console_print(id, "[DM] Duel Mod is not currently enabled.")
return PLUGIN_HANDLED
}
new const iIndex = id - 1
new szTargetName[32]
read_argv(1, szTargetName, 31)
new tid = cmd_target(id, szTargetName, 12)
if (tid)
{
new const iTargetIndex = tid - 1
new iMode = get_cvar_num("mp_gamemode")
if (iMode == 1)
{
new szTeam[12]
get_user_team(id, szTeam, 11)
new szTargetTeam[12]
get_user_team(tid, szTargetTeam, 11)
if (equal(szTeam, szTargetTeam))
{
console_print(id, "[DM] You cannot challenge your teammate to a duel!")
return PLUGIN_HANDLED
}
if (equal(szTeam, "") || equal(szTargetTeam, ""))
{
console_print(id, "[DM] You cannot make a challenge or be challenged from spectator mode!")
return PLUGIN_HANDLED
}
}
if (!g_bDueling[iIndex] && !g_bDueling[iTargetIndex])
{
new szName[32]
get_user_name(id, szName, 31)
new szTargetName[32]
get_user_name(tid, szTargetName, 31)
client_print(id, print_chat, "[DM] You have challenged %s to a duel!", szTargetName)
client_print(tid, print_chat, "[DM] %s has challenged you to a duel!", szName)
g_iOpponent[iIndex] = tid
g_iOpponent[iTargetIndex] = id
g_mDuelMenu[iTargetIndex] = menu_create("Duel Menu", "fnDuelMenu")
menu_additem(g_mDuelMenu[iTargetIndex], "Accept", "1")
menu_additem(g_mDuelMenu[iTargetIndex], "Decline", "2")
new szTitle[48]
formatex(szTitle, 47, "%s challenges you:", szName)
menu_setprop(g_mDuelMenu[iTargetIndex], MPROP_TITLE, szTitle)
menu_setprop(g_mDuelMenu[iTargetIndex], MPROP_PERPAGE, 0)
menu_setprop(g_mDuelMenu[iTargetIndex], MPROP_EXIT, MEXIT_NEVER)
menu_display(tid, g_mDuelMenu[iTargetIndex], 0)
}
else
{
if (g_bDueling[iTargetIndex])
{
new szTargetName[32]
get_user_name(tid, szTargetName, 31)
console_print(id, "[DM] %s is already in a duel.", szTargetName)
}
else
{
new szOpponentName[32]
get_user_name(g_iOpponent[iIndex], szOpponentName, 31)
console_print(id, "[DM] You're already dueling %s!", szOpponentName)
}
}
}
else
client_print(id, print_chat, "[DM] You must be facing an opponent to challenge them to a duel!")
return PLUGIN_HANDLED
}
public concmd_stats(id)
{
if (!get_pcvar_num(g_pEnabled))
{
console_print(id, "[DM] Duel Mod is not currently enabled.")
return PLUGIN_HANDLED
}
new iPlayers[32], iPlayerNum
get_players(iPlayers, iPlayerNum)
console_print(id, "Name | Total Kills | Total Deaths | Duel Wins | Duel Losses")
for (new i = 0, szName[32], iPlayerIndex; i < iPlayerNum; i++)
{
iPlayerIndex = iPlayers[i] - 1
get_user_name(iPlayers[i], szName, 31)
console_print(id, "%s | %d | %d | %d | %d", szName, g_iTotalKills[iPlayerIndex], g_iTotalDeaths[iPlayerIndex], g_iDuelWins[iPlayerIndex], g_iDuelLosses[iPlayerIndex])
}
return PLUGIN_HANDLED
}
public cmd_duel(id)
{
if (!get_pcvar_num(g_pEnabled))
{
client_print(id, print_chat, "[DM] Duel Mod is not currently enabled.")
return PLUGIN_HANDLED
}
new const iIndex = id - 1
new tid, body
get_user_aiming(id, tid, body, 9999)
if (tid)
{
new const iTargetIndex = tid - 1
if (!g_bDueling[iIndex] && !g_bDueling[iTargetIndex])
{
new szName[32]
get_user_name(id, szName, 31)
new szTargetName[32]
get_user_name(tid, szTargetName, 31)
client_print(id, print_chat, "[DM] You have challenged %s to a duel!", szTargetName)
client_print(tid, print_chat, "[DM] %s has challenged you to a duel!", szName)
g_iOpponent[iIndex] = tid
g_iOpponent[iTargetIndex] = id
g_mDuelMenu[iTargetIndex] = menu_create("Duel Menu", "fnDuelMenu")
menu_additem(g_mDuelMenu[iTargetIndex], "Accept", "1")
menu_additem(g_mDuelMenu[iTargetIndex], "Decline", "2")
new szTitle[48]
formatex(szTitle, 47, "%s challenges you:", szName)
menu_setprop(g_mDuelMenu[iTargetIndex], MPROP_TITLE, szTitle)
menu_setprop(g_mDuelMenu[iTargetIndex], MPROP_PERPAGE, 0)
menu_setprop(g_mDuelMenu[iTargetIndex], MPROP_EXIT, MEXIT_NEVER)
menu_display(tid, g_mDuelMenu[iTargetIndex], 0)
}
else
{
if (g_bDueling[iTargetIndex])
{
new szTargetName[32]
get_user_name(tid, szTargetName, 31)
client_print(id, print_chat, "[DM] %s is already in a duel.", szTargetName)
}
else
{
new szOpponentName[32]
get_user_name(g_iOpponent[iIndex], szOpponentName, 31)
client_print(id, print_chat, "[DM] You're already dueling %s!")
}
}
}
else
client_print(id, print_chat, "[DM] You must be facing an opponent to challenge them to a duel!")
return PLUGIN_HANDLED
}
public fnDuelMenu(id, menu, item)
{
if (item == MENU_EXIT)
{
menu_destroy(menu)
return PLUGIN_HANDLED
}
new const iIndex = id - 1, iTargetIndex = g_iOpponent[iIndex] - 1
new szData[6], access, callback
menu_item_getinfo(menu, item, access, szData, 5, _, _, callback)
new iKey = str_to_num(szData)
if (iKey == 1)
{
g_bDueling[iIndex] = true
g_bDueling[iTargetIndex] = true
new szOpponentName[32]
get_user_name(id, szOpponentName, 31)
client_print(id, print_chat, "[DM] You have accepted the challenge.")
client_print(g_iOpponent[iIndex], print_chat, "[DM] %s has accepted your challenge.", szOpponentName)
set_user_health(id, 100)
set_user_health(g_iOpponent[iIndex], 100)
client_print(id, print_chat, "[DM] Your health has been reset to 100! FIGHT!")
client_print(g_iOpponent[iIndex], print_chat, "[DM] Your health has been reset to 100! FIGHT!")
set_user_rendering(id, kRenderFxGlowShell, 255, 255, 255, kRenderNormal, 5)
set_user_rendering(g_iOpponent[iIndex], kRenderFxGlowShell, 255, 255, 255, kRenderNormal, 5)
g_iHealth[iIndex] = get_user_health(id)
g_iHealth[iTargetIndex] = get_user_health(g_iOpponent[iIndex])
}
else
{
new szName[32]
get_user_name(g_iOpponent[iIndex], szName, 31)
new szOpponentName[32]
get_user_name(id, szOpponentName, 31)
client_print(id, print_chat, "[DM] You have declined a duel with %s.", szOpponentName)
client_print(g_iOpponent[iIndex], print_chat, "[DM] %s has declined a duel with you.", szName)
}
menu_destroy(menu)
return PLUGIN_CONTINUE
}
public cmd_cancel(id)
{
new const iIndex = id - 1
if (g_bDueling[iIndex])
{
new const iTargetIndex = g_iOpponent[iIndex] - 1
new szName[32]
get_user_name(id, szName, 31)
new szOpponentName[32]
get_user_name(g_iOpponent[iIndex], szOpponentName, 31)
set_user_rendering(id, kRenderFxNone, 0, 0, 0, kRenderNormal, 0)
set_user_rendering(g_iOpponent[iIndex], kRenderFxNone, 0, 0, 0, kRenderNormal, 0)
client_print(id, print_chat, "[DM] You have cancelled your duel with %s.", szOpponentName)
client_print(g_iOpponent[iIndex], print_chat, "[DM] %s has cancelled their duel with you.", szName)
g_bDueling[iIndex] = false
g_bDueling[iTargetIndex] = false
g_iOpponent[iIndex] = 0
g_iOpponent[iTargetIndex] = 0
}
else
client_print(id, print_chat, "[DM] You aren't currently in a duel.")
return PLUGIN_HANDLED
}
public cmd_author(id)
{
new szName[32]
get_user_name(id, szName, 31)
client_print(0, print_chat, "[DM] ^"%s^": This plugin was written by Spunky.", szName)
return PLUGIN_HANDLED
}