From aef0d1c1268ab7d4bc18996c9c6b4da16a40aadc Mon Sep 17 00:00:00 2001 From: navewindre Date: Mon, 4 Dec 2023 18:06:10 +0100 Subject: bbbbbbbbwaaaaaaaaaaa --- sourcemod/scripting/gokz-localranks/api.sp | 120 +++++ sourcemod/scripting/gokz-localranks/commands.sp | 506 +++++++++++++++++++++ .../scripting/gokz-localranks/db/cache_pbs.sp | 62 +++ .../scripting/gokz-localranks/db/cache_records.sp | 54 +++ .../scripting/gokz-localranks/db/create_tables.sp | 27 ++ .../scripting/gokz-localranks/db/display_js.sp | 325 +++++++++++++ .../scripting/gokz-localranks/db/get_completion.sp | 155 +++++++ sourcemod/scripting/gokz-localranks/db/helpers.sp | 91 ++++ sourcemod/scripting/gokz-localranks/db/js_top.sp | 286 ++++++++++++ sourcemod/scripting/gokz-localranks/db/map_top.sp | 388 ++++++++++++++++ .../scripting/gokz-localranks/db/player_top.sp | 165 +++++++ .../scripting/gokz-localranks/db/print_average.sp | 152 +++++++ sourcemod/scripting/gokz-localranks/db/print_js.sp | 108 +++++ .../scripting/gokz-localranks/db/print_pbs.sp | 266 +++++++++++ .../scripting/gokz-localranks/db/print_records.sp | 173 +++++++ .../gokz-localranks/db/process_new_time.sp | 157 +++++++ .../scripting/gokz-localranks/db/recent_records.sp | 171 +++++++ sourcemod/scripting/gokz-localranks/db/sql.sp | 411 +++++++++++++++++ .../gokz-localranks/db/update_ranked_map_pool.sp | 104 +++++ sourcemod/scripting/gokz-localranks/misc.sp | 319 +++++++++++++ 20 files changed, 4040 insertions(+) create mode 100644 sourcemod/scripting/gokz-localranks/api.sp create mode 100644 sourcemod/scripting/gokz-localranks/commands.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/cache_pbs.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/cache_records.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/create_tables.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/display_js.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/get_completion.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/helpers.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/js_top.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/map_top.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/player_top.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/print_average.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/print_js.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/print_pbs.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/print_records.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/process_new_time.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/recent_records.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/sql.sp create mode 100644 sourcemod/scripting/gokz-localranks/db/update_ranked_map_pool.sp create mode 100644 sourcemod/scripting/gokz-localranks/misc.sp (limited to 'sourcemod/scripting/gokz-localranks') diff --git a/sourcemod/scripting/gokz-localranks/api.sp b/sourcemod/scripting/gokz-localranks/api.sp new file mode 100644 index 0000000..34b3ece --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/api.sp @@ -0,0 +1,120 @@ +static GlobalForward H_OnTimeProcessed; +static GlobalForward H_OnNewRecord; +static GlobalForward H_OnRecordMissed; +static GlobalForward H_OnPBMissed; + + + +// =====[ FORWARDS ]===== + +void CreateGlobalForwards() +{ + H_OnTimeProcessed = new GlobalForward("GOKZ_LR_OnTimeProcessed", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Float, Param_Cell, Param_Cell, Param_Float, Param_Cell, Param_Cell, Param_Cell, Param_Float, Param_Cell, Param_Cell); + H_OnNewRecord = new GlobalForward("GOKZ_LR_OnNewRecord", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Float, Param_Cell, Param_Float, Param_Cell); + H_OnRecordMissed = new GlobalForward("GOKZ_LR_OnRecordMissed", ET_Ignore, Param_Cell, Param_Float, Param_Cell, Param_Cell, Param_Cell, Param_Cell); + H_OnPBMissed = new GlobalForward("GOKZ_LR_OnPBMissed", ET_Ignore, Param_Cell, Param_Float, Param_Cell, Param_Cell, Param_Cell, Param_Cell); +} + +void Call_OnTimeProcessed( + int client, + int steamID, + int mapID, + int course, + int mode, + int style, + float runTime, + int teleports, + bool firstTime, + float pbDiff, + int rank, + int maxRank, + bool firstTimePro, + float pbDiffPro, + int rankPro, + int maxRankPro) +{ + Call_StartForward(H_OnTimeProcessed); + Call_PushCell(client); + Call_PushCell(steamID); + Call_PushCell(mapID); + Call_PushCell(course); + Call_PushCell(mode); + Call_PushCell(style); + Call_PushFloat(runTime); + Call_PushCell(teleports); + Call_PushCell(firstTime); + Call_PushFloat(pbDiff); + Call_PushCell(rank); + Call_PushCell(maxRank); + Call_PushCell(firstTimePro); + Call_PushFloat(pbDiffPro); + Call_PushCell(rankPro); + Call_PushCell(maxRankPro); + Call_Finish(); +} + +void Call_OnNewRecord(int client, int steamID, int mapID, int course, int mode, int style, int recordType, float pbDiff, int teleportsUsed) +{ + Call_StartForward(H_OnNewRecord); + Call_PushCell(client); + Call_PushCell(steamID); + Call_PushCell(mapID); + Call_PushCell(course); + Call_PushCell(mode); + Call_PushCell(style); + Call_PushCell(recordType); + Call_PushFloat(pbDiff); + Call_PushCell(teleportsUsed); + Call_Finish(); +} + +void Call_OnRecordMissed(int client, float recordTime, int course, int mode, int style, int recordType) +{ + Call_StartForward(H_OnRecordMissed); + Call_PushCell(client); + Call_PushFloat(recordTime); + Call_PushCell(course); + Call_PushCell(mode); + Call_PushCell(style); + Call_PushCell(recordType); + Call_Finish(); +} + +void Call_OnPBMissed(int client, float pbTime, int course, int mode, int style, int recordType) +{ + Call_StartForward(H_OnPBMissed); + Call_PushCell(client); + Call_PushFloat(pbTime); + Call_PushCell(course); + Call_PushCell(mode); + Call_PushCell(style); + Call_PushCell(recordType); + Call_Finish(); +} + + + +// =====[ NATIVES ]===== + +void CreateNatives() +{ + CreateNative("GOKZ_LR_GetRecordMissed", Native_GetRecordMissed); + CreateNative("GOKZ_LR_GetPBMissed", Native_GetPBMissed); + CreateNative("GOKZ_LR_ReopenMapTopMenu", Native_ReopenMapTopMenu); +} + +public int Native_GetRecordMissed(Handle plugin, int numParams) +{ + return view_as(gB_RecordMissed[GetNativeCell(1)][GetNativeCell(2)]); +} + +public int Native_GetPBMissed(Handle plugin, int numParams) +{ + return view_as(gB_PBMissed[GetNativeCell(1)][GetNativeCell(2)]); +} + +public int Native_ReopenMapTopMenu(Handle plugin, int numParams) +{ + ReopenMapTopMenu(GetNativeCell(1)); + return 0; +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/commands.sp b/sourcemod/scripting/gokz-localranks/commands.sp new file mode 100644 index 0000000..44063af --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/commands.sp @@ -0,0 +1,506 @@ +static float lastCommandTime[MAXPLAYERS + 1]; + + + +void RegisterCommands() +{ + RegConsoleCmd("sm_top", CommandTop, "[KZ] Open a menu showing the top record holders."); + RegConsoleCmd("sm_maptop", CommandMapTop, "[KZ] Open a menu showing the top main course times of a map. Usage: !maptop "); + RegConsoleCmd("sm_bmaptop", CommandBMapTop, "[KZ] Open a menu showing the top bonus times of a map. Usage: !bmaptop <#bonus> "); + RegConsoleCmd("sm_bonustop", CommandBMapTop, "[KZ] Open a menu showing the top bonus times of a map. Usage: !bonustop <#bonus> "); + RegConsoleCmd("sm_btop", CommandBMapTop, "[KZ] Open a menu showing the top bonus times of a map. Usage: !btop <#bonus> "); + RegConsoleCmd("sm_pb", CommandPB, "[KZ] Show PB main course times and ranks in chat. Usage: !pb "); + RegConsoleCmd("sm_bpb", CommandBPB, "[KZ] Show PB bonus times and ranks in chat. Usage: !bpb <#bonus> "); + RegConsoleCmd("sm_wr", CommandWR, "[KZ] Show main course record times in chat. Usage: !wr "); + RegConsoleCmd("sm_bwr", CommandBWR, "[KZ] Show bonus record times in chat. Usage: !bwr <#bonus> "); + RegConsoleCmd("sm_avg", CommandAVG, "[KZ] Show the average main course run time in chat. Usage !avg "); + RegConsoleCmd("sm_bavg", CommandBAVG, "[KZ] Show the average bonus run time in chat. Usage !bavg <#bonus> "); + RegConsoleCmd("sm_pc", CommandPC, "[KZ] Show course completion in chat. Usage: !pc "); + RegConsoleCmd("sm_rr", CommandRecentRecords, "[KZ] Open a menu showing recently broken records."); + RegConsoleCmd("sm_latest", CommandRecentRecords, "[KZ] Open a menu showing recently broken records."); + + RegConsoleCmd("sm_ljpb", CommandLJPB, "[KZ] Show PB Long Jump in chat. Usage: !ljpb "); + RegConsoleCmd("sm_bhpb", CommandBHPB, "[KZ] Show PB Bunnyhop in chat. Usage: !bhpb "); + RegConsoleCmd("sm_lbhpb", CommandLBHPB, "[KZ] Show PB Lowpre Bunnyhop in chat. Usage: !lbhpb "); + RegConsoleCmd("sm_mbhpb", CommandMBHPB, "[KZ] Show PB Multi Bunnyhop in chat. Usage: !mbhpb "); + RegConsoleCmd("sm_wjpb", CommandWJPB, "[KZ] Show PB Weird Jump in chat. Usage: !wjpb "); + RegConsoleCmd("sm_lwjpb", CommandLWJPB, "[KZ] Show PB Lowpre Weird Jump in chat. Usage: !lwjpb "); + RegConsoleCmd("sm_lajpb", CommandLAJPB, "[KZ] Show PB Ladder Jump in chat. Usage: !lajpb "); + RegConsoleCmd("sm_lahpb", CommandLAHPB, "[KZ] Show PB Ladderhop in chat. Usage: !lahpb "); + RegConsoleCmd("sm_jbpb", CommandJBPB, "[KZ] Show PB Jumpbug in chat. Usage: !jbpb "); + RegConsoleCmd("sm_js", CommandJS, "[KZ] Open a menu showing jumpstat PBs. Usage: !js "); + RegConsoleCmd("sm_jumpstats", CommandJS, "[KZ] Open a menu showing jumpstat PBs. Usage: !jumpstats "); + RegConsoleCmd("sm_jstop", CommandJSTop, "[KZ] Open a menu showing the top jumpstats."); + RegConsoleCmd("sm_jumptop", CommandJSTop, "[KZ] Open a menu showing the top jumpstats."); + + RegAdminCmd("sm_updatemappool", CommandUpdateMapPool, ADMFLAG_ROOT, "[KZ] Update the ranked map pool with the list of maps in cfg/sourcemod/gokz/gokz-localranks-mappool.cfg."); +} + +public Action CommandTop(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + DisplayPlayerTopModeMenu(client); + return Plugin_Handled; +} + +public Action CommandMapTop(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args == 0) + { // Open map top for current map + DB_OpenMapTopModeMenu(client, GOKZ_DB_GetCurrentMapID(), 0); + } + else if (args >= 1) + { // Open map top for specified map + char specifiedMap[33]; + GetCmdArg(1, specifiedMap, sizeof(specifiedMap)); + DB_OpenMapTopModeMenu_FindMap(client, specifiedMap, 0); + } + return Plugin_Handled; +} + +public Action CommandBMapTop(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args == 0) + { // Open Bonus 1 top for current map + DB_OpenMapTopModeMenu(client, GOKZ_DB_GetCurrentMapID(), 1); + } + else if (args == 1) + { // Open specified Bonus # top for current map + char argBonus[4]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_OpenMapTopModeMenu(client, GOKZ_DB_GetCurrentMapID(), bonus); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + else if (args >= 2) + { // Open specified bonus top for specified map + char argBonus[4], argMap[33]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + GetCmdArg(2, argMap, sizeof(argMap)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_OpenMapTopModeMenu_FindMap(client, argMap, bonus); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + return Plugin_Handled; +} + +public Action CommandPB(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args == 0) + { // Print their PBs for current map and their current mode + DB_PrintPBs(client, GetSteamAccountID(client), GOKZ_DB_GetCurrentMapID(), 0, GOKZ_GetCoreOption(client, Option_Mode)); + if (gB_GOKZGlobal) + { + char steamid[32]; + GetClientAuthId(client, AuthId_Steam2, steamid, sizeof(steamid)); + GOKZ_GL_PrintRecords(client, "", 0, GOKZ_GetCoreOption(client, Option_Mode), steamid); + } + } + else if (args == 1) + { // Print their PBs for specified map and their current mode + char argMap[33]; + GetCmdArg(1, argMap, sizeof(argMap)); + DB_PrintPBs_FindMap(client, GetSteamAccountID(client), argMap, 0, GOKZ_GetCoreOption(client, Option_Mode)); + } + else if (args >= 2) + { // Print specified player's PBs for specified map and their current mode + char argMap[33], argPlayer[MAX_NAME_LENGTH]; + GetCmdArg(1, argMap, sizeof(argMap)); + GetCmdArg(2, argPlayer, sizeof(argPlayer)); + DB_PrintPBs_FindPlayerAndMap(client, argPlayer, argMap, 0, GOKZ_GetCoreOption(client, Option_Mode)); + } + return Plugin_Handled; +} + +public Action CommandBPB(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args == 0) + { // Print their Bonus 1 PBs for current map and their current mode + DB_PrintPBs(client, GetSteamAccountID(client), GOKZ_DB_GetCurrentMapID(), 1, GOKZ_GetCoreOption(client, Option_Mode)); + if (gB_GOKZGlobal) + { + char steamid[32]; + GetClientAuthId(client, AuthId_Steam2, steamid, sizeof(steamid)); + GOKZ_GL_PrintRecords(client, "", 1, GOKZ_GetCoreOption(client, Option_Mode), steamid); + } + } + else if (args == 1) + { // Print their specified Bonus # PBs for current map and their current mode + char argBonus[4]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_PrintPBs(client, GetSteamAccountID(client), GOKZ_DB_GetCurrentMapID(), bonus, GOKZ_GetCoreOption(client, Option_Mode)); + if (gB_GOKZGlobal) + { + char steamid[32]; + GetClientAuthId(client, AuthId_Steam2, steamid, sizeof(steamid)); + GOKZ_GL_PrintRecords(client, "", bonus, GOKZ_GetCoreOption(client, Option_Mode), steamid); + } + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + else if (args == 2) + { // Print their specified Bonus # PBs for specified map and their current mode + char argBonus[4], argMap[33]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + GetCmdArg(2, argMap, sizeof(argMap)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_PrintPBs_FindMap(client, GetSteamAccountID(client), argMap, bonus, GOKZ_GetCoreOption(client, Option_Mode)); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + else if (args >= 3) + { // Print specified player's specified Bonus # PBs for specified map and their current mode + char argBonus[4], argMap[33], argPlayer[MAX_NAME_LENGTH]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + GetCmdArg(2, argMap, sizeof(argMap)); + GetCmdArg(3, argPlayer, sizeof(argPlayer)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_PrintPBs_FindPlayerAndMap(client, argPlayer, argMap, bonus, GOKZ_GetCoreOption(client, Option_Mode)); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + return Plugin_Handled; +} + +public Action CommandWR(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args == 0) + { // Print record times for current map and their current mode + DB_PrintRecords(client, GOKZ_DB_GetCurrentMapID(), 0, GOKZ_GetCoreOption(client, Option_Mode)); + if (gB_GOKZGlobal) + { + GOKZ_GL_PrintRecords(client, "", 0, GOKZ_GetCoreOption(client, Option_Mode)); + } + } + else if (args >= 1) + { // Print record times for specified map and their current mode + char argMap[33]; + GetCmdArg(1, argMap, sizeof(argMap)); + DB_PrintRecords_FindMap(client, argMap, 0, GOKZ_GetCoreOption(client, Option_Mode)); + } + return Plugin_Handled; +} + +public Action CommandBWR(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args == 0) + { // Print Bonus 1 record times for current map and their current mode + DB_PrintRecords(client, GOKZ_DB_GetCurrentMapID(), 1, GOKZ_GetCoreOption(client, Option_Mode)); + if (gB_GOKZGlobal) + { + GOKZ_GL_PrintRecords(client, "", 1, GOKZ_GetCoreOption(client, Option_Mode)); + } + } + else if (args == 1) + { // Print specified Bonus # record times for current map and their current mode + char argBonus[4]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_PrintRecords(client, GOKZ_DB_GetCurrentMapID(), bonus, GOKZ_GetCoreOption(client, Option_Mode)); + if (gB_GOKZGlobal) + { + GOKZ_GL_PrintRecords(client, "", bonus, GOKZ_GetCoreOption(client, Option_Mode)); + } + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + else if (args >= 2) + { // Print specified Bonus # record times for specified map and their current mode + char argBonus[4], argMap[33]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + GetCmdArg(2, argMap, sizeof(argMap)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_PrintRecords_FindMap(client, argMap, bonus, GOKZ_GetCoreOption(client, Option_Mode)); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + return Plugin_Handled; +} + +public Action CommandAVG(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args == 0) + { // Print average times for current map and their current mode + DB_PrintAverage(client, GOKZ_DB_GetCurrentMapID(), 0, GOKZ_GetCoreOption(client, Option_Mode)); + } + else if (args >= 1) + { // Print average times for specified map and their current mode + char argMap[33]; + GetCmdArg(1, argMap, sizeof(argMap)); + DB_PrintAverage_FindMap(client, argMap, 0, GOKZ_GetCoreOption(client, Option_Mode)); + } + return Plugin_Handled; +} + +public Action CommandBAVG(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args == 0) + { // Print Bonus 1 average times for current map and their current mode + DB_PrintAverage(client, GOKZ_DB_GetCurrentMapID(), 1, GOKZ_GetCoreOption(client, Option_Mode)); + } + else if (args == 1) + { // Print specified Bonus # average times for current map and their current mode + char argBonus[4]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_PrintAverage(client, GOKZ_DB_GetCurrentMapID(), bonus, GOKZ_GetCoreOption(client, Option_Mode)); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + else if (args >= 2) + { // Print specified Bonus # average times for specified map and their current mode + char argBonus[4], argMap[33]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + GetCmdArg(2, argMap, sizeof(argMap)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DB_PrintAverage_FindMap(client, argMap, bonus, GOKZ_GetCoreOption(client, Option_Mode)); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + return Plugin_Handled; +} + +public Action CommandPC(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args < 1) + { + DB_GetCompletion(client, GetSteamAccountID(client), GOKZ_GetCoreOption(client, Option_Mode), true); + } + else if (args >= 1) + { // Print record times for specified map and their current mode + char argPlayer[MAX_NAME_LENGTH]; + GetCmdArg(1, argPlayer, sizeof(argPlayer)); + DB_GetCompletion_FindPlayer(client, argPlayer, GOKZ_GetCoreOption(client, Option_Mode)); + } + return Plugin_Handled; +} + +public Action CommandRecentRecords(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + DisplayRecentRecordsModeMenu(client); + return Plugin_Handled; +} + +public Action CommandUpdateMapPool(int client, int args) +{ + DB_UpdateRankedMapPool(client); + return Plugin_Handled; +} + +public Action CommandLJPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_LongJump); + return Plugin_Handled; +} + +public Action CommandBHPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_Bhop); + return Plugin_Handled; +} + +public Action CommandLBHPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_LowpreBhop); + return Plugin_Handled; +} + +public Action CommandMBHPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_MultiBhop); + return Plugin_Handled; +} + +public Action CommandWJPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_WeirdJump); + return Plugin_Handled; +} + +public Action CommandLWJPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_LowpreWeirdJump); + return Plugin_Handled; +} + +public Action CommandLAJPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_LadderJump); + return Plugin_Handled; +} + +public Action CommandLAHPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_Ladderhop); + return Plugin_Handled; +} + +public Action CommandJBPB(int client, int args) +{ + DisplayJumpstatRecordCommand(client, args, JumpType_Jumpbug); + return Plugin_Handled; +} + +public Action CommandJS(int client, int args) +{ + if (IsSpammingCommands(client)) + { + return Plugin_Handled; + } + + if (args < 1) + { + DB_OpenJumpStatsModeMenu(client, GetSteamAccountID(client)); + } + else if (args >= 1) + { + char argPlayer[MAX_NAME_LENGTH]; + GetCmdArg(1, argPlayer, sizeof(argPlayer)); + DB_OpenJumpStatsModeMenu_FindPlayer(client, argPlayer); + } + return Plugin_Handled; +} + +public Action CommandJSTop(int client, int args) +{ + DisplayJumpTopModeMenu(client); + return Plugin_Handled; +} + +void DisplayJumpstatRecordCommand(int client, int args, int jumpType) +{ + if (args >= 1) + { + char argJumper[33]; + GetCmdArg(1, argJumper, sizeof(argJumper)); + DisplayJumpstatRecord(client, jumpType, argJumper); + } + else + { + DisplayJumpstatRecord(client, jumpType); + } +} + + + +// =====[ PRIVATE ]===== + +bool IsSpammingCommands(int client, bool printMessage = true) +{ + float currentTime = GetEngineTime(); + float timeSinceLastCommand = currentTime - lastCommandTime[client]; + if (timeSinceLastCommand < LR_COMMAND_COOLDOWN) + { + if (printMessage) + { + GOKZ_PrintToChat(client, true, "%t", "Please Wait Before Using Command", LR_COMMAND_COOLDOWN - timeSinceLastCommand + 0.1); + } + return true; + } + + // Not spamming commands - all good! + lastCommandTime[client] = currentTime; + return false; +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/cache_pbs.sp b/sourcemod/scripting/gokz-localranks/db/cache_pbs.sp new file mode 100644 index 0000000..12c3ed2 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/cache_pbs.sp @@ -0,0 +1,62 @@ +/* + Caches the player's personal best times on the map. +*/ + + + +void DB_CachePBs(int client, int steamID) +{ + char query[1024]; + + Transaction txn = SQL_CreateTransaction(); + + // Reset PB exists array + for (int course = 0; course < GOKZ_MAX_COURSES; course++) + { + for (int mode = 0; mode < MODE_COUNT; mode++) + { + for (int timeType = 0; timeType < TIMETYPE_COUNT; timeType++) + { + gB_PBExistsCache[client][course][mode][timeType] = false; + } + } + } + + int mapID = GOKZ_DB_GetCurrentMapID(); + + // Get Map PBs + FormatEx(query, sizeof(query), sql_getpbs, steamID, mapID); + txn.AddQuery(query); + // Get PRO PBs + FormatEx(query, sizeof(query), sql_getpbspro, steamID, mapID); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_CachePBs, DB_TxnFailure_Generic, GetClientUserId(client), DBPrio_High); +} + +public void DB_TxnSuccess_CachePBs(Handle db, int userID, int numQueries, Handle[] results, any[] queryData) +{ + int client = GetClientOfUserId(userID); + if (client < 1 || client > MaxClients || !IsClientAuthorized(client) || IsFakeClient(client)) + { + return; + } + + int course, mode; + + while (SQL_FetchRow(results[0])) + { + course = SQL_FetchInt(results[0], 1); + mode = SQL_FetchInt(results[0], 2); + gB_PBExistsCache[client][course][mode][TimeType_Nub] = true; + gF_PBTimesCache[client][course][mode][TimeType_Nub] = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[0], 0)); + } + + while (SQL_FetchRow(results[1])) + { + course = SQL_FetchInt(results[1], 1); + mode = SQL_FetchInt(results[1], 2); + gB_PBExistsCache[client][course][mode][TimeType_Pro] = true; + gF_PBTimesCache[client][course][mode][TimeType_Pro] = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[1], 0)); + } +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/cache_records.sp b/sourcemod/scripting/gokz-localranks/db/cache_records.sp new file mode 100644 index 0000000..611b13c --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/cache_records.sp @@ -0,0 +1,54 @@ +/* + Caches the record times on the map. +*/ + + + +void DB_CacheRecords(int mapID) +{ + char query[1024]; + + Transaction txn = SQL_CreateTransaction(); + + // Reset record exists array + for (int course = 0; course < GOKZ_MAX_COURSES; course++) + { + for (int mode = 0; mode < MODE_COUNT; mode++) + { + for (int timeType = 0; timeType < TIMETYPE_COUNT; timeType++) + { + gB_RecordExistsCache[course][mode][timeType] = false; + } + } + } + + // Get Map WRs + FormatEx(query, sizeof(query), sql_getwrs, mapID); + txn.AddQuery(query); + // Get PRO WRs + FormatEx(query, sizeof(query), sql_getwrspro, mapID); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_CacheRecords, DB_TxnFailure_Generic, _, DBPrio_High); +} + +public void DB_TxnSuccess_CacheRecords(Handle db, any data, int numQueries, Handle[] results, any[] queryData) +{ + int course, mode; + + while (SQL_FetchRow(results[0])) + { + course = SQL_FetchInt(results[0], 1); + mode = SQL_FetchInt(results[0], 2); + gB_RecordExistsCache[course][mode][TimeType_Nub] = true; + gF_RecordTimesCache[course][mode][TimeType_Nub] = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[0], 0)); + } + + while (SQL_FetchRow(results[1])) + { + course = SQL_FetchInt(results[1], 1); + mode = SQL_FetchInt(results[1], 2); + gB_RecordExistsCache[course][mode][TimeType_Pro] = true; + gF_RecordTimesCache[course][mode][TimeType_Pro] = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[1], 0)); + } +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/create_tables.sp b/sourcemod/scripting/gokz-localranks/db/create_tables.sp new file mode 100644 index 0000000..a15f67c --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/create_tables.sp @@ -0,0 +1,27 @@ +/* + Table creation and alteration. +*/ + + + +void DB_CreateTables() +{ + Transaction txn = SQL_CreateTransaction(); + + // Create/alter database tables + switch (g_DBType) + { + case DatabaseType_SQLite: + { + txn.AddQuery(sqlite_maps_alter1); + } + case DatabaseType_MySQL: + { + txn.AddQuery(mysql_maps_alter1); + } + } + + // No error logs for this transaction as it will always throw an error + // if the column already exists, which is more annoying than helpful. + SQL_ExecuteTransaction(gH_DB, txn, _, _, _, DBPrio_High); +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/display_js.sp b/sourcemod/scripting/gokz-localranks/db/display_js.sp new file mode 100644 index 0000000..779148f --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/display_js.sp @@ -0,0 +1,325 @@ +/* + Displays player's best jumpstats in a menu. +*/ + +static int jumpStatsTargetSteamID[MAXPLAYERS + 1]; +static char jumpStatsTargetAlias[MAXPLAYERS + 1][MAX_NAME_LENGTH]; +static int jumpStatsMode[MAXPLAYERS + 1]; + + + +// =====[ JUMPSTATS MODE ]===== + +void DB_OpenJumpStatsModeMenu(int client, int targetSteamID) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(targetSteamID); + + Transaction txn = SQL_CreateTransaction(); + + // Retrieve name of target + FormatEx(query, sizeof(query), sql_players_getalias, targetSteamID); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_OpenJumpStatsModeMenu, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_OpenJumpStatsModeMenu(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int targetSteamID = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + // Get name of target + if (!SQL_FetchRow(results[0])) + { + return; + } + SQL_FetchString(results[0], 0, jumpStatsTargetAlias[client], sizeof(jumpStatsTargetAlias[])); + + jumpStatsTargetSteamID[client] = targetSteamID; + DisplayJumpStatsModeMenu(client); +} + +void DB_OpenJumpStatsModeMenu_FindPlayer(int client, const char[] target) +{ + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteString(target); + + DB_FindPlayer(target, DB_TxnSuccess_OpenJumpStatsModeMenu_FindPlayer, data, DBPrio_Low); +} + +public void DB_TxnSuccess_OpenJumpStatsModeMenu_FindPlayer(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + char playerSearch[33]; + data.ReadString(playerSearch, sizeof(playerSearch)); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + else if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Player Not Found", playerSearch); + return; + } + else if (SQL_FetchRow(results[0])) + { + DB_OpenJumpStatsModeMenu(client, SQL_FetchInt(results[0], 0)); + } +} + + + +// =====[ MENUS ]===== + +static void DisplayJumpStatsModeMenu(int client) +{ + Menu menu = new Menu(MenuHandler_JumpStatsMode); + menu.SetTitle("%T", "Jump Stats Mode Menu - Title", client, jumpStatsTargetAlias[client]); + GOKZ_MenuAddModeItems(client, menu, false); + menu.Display(client, MENU_TIME_FOREVER); +} + +static void DisplayJumpStatsBlockTypeMenu(int client, int mode) +{ + jumpStatsMode[client] = mode; + + Menu menu = new Menu(MenuHandler_JumpStatsBlockType); + menu.SetTitle("%T", "Jump Stats Block Type Menu - Title", client, jumpStatsTargetAlias[client], gC_ModeNames[jumpStatsMode[client]]); + JumpStatsBlockTypeMenuAddItems(client, menu); + menu.Display(client, MENU_TIME_FOREVER); +} + +static void JumpStatsBlockTypeMenuAddItems(int client, Menu menu) +{ + char str[64]; + FormatEx(str, sizeof(str), "%T", "Jump Records", client); + menu.AddItem("jump", str); + FormatEx(str, sizeof(str), "%T %T", "Block", client, "Jump Records", client); + menu.AddItem("blockjump", str); +} + + + +// =====[ JUMPSTATS ]===== + +void DB_OpenJumpStats(int client, int targetSteamID, int mode, int blockType) +{ + char query[1024]; + Transaction txn = SQL_CreateTransaction(); + + // Get alias + FormatEx(query, sizeof(query), sql_players_getalias, targetSteamID); + txn.AddQuery(query); + + // Get jumpstat pbs + if (blockType == 0) + { + FormatEx(query, sizeof(query), sql_jumpstats_getpbs, targetSteamID, mode); + } + else + { + FormatEx(query, sizeof(query), sql_jumpstats_getblockpbs, targetSteamID, mode); + } + txn.AddQuery(query); + + DataPack datapack = new DataPack(); + datapack.WriteCell(GetClientUserId(client)); + datapack.WriteCell(targetSteamID); + datapack.WriteCell(mode); + datapack.WriteCell(blockType); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_OpenJumpStats, DB_TxnFailure_Generic_DataPack, datapack, DBPrio_Low); +} + +public void DB_TxnSuccess_OpenJumpStats(Handle db, DataPack datapack, int numQueries, Handle[] results, any[] queryData) +{ + datapack.Reset(); + int client = GetClientOfUserId(datapack.ReadCell()); + int targetSteamID = datapack.ReadCell(); + int mode = datapack.ReadCell(); + int blockType = datapack.ReadCell(); + delete datapack; + + if (!IsValidClient(client)) + { + return; + } + + // Get target name + if (!SQL_FetchRow(results[0])) + { + return; + } + char alias[MAX_NAME_LENGTH]; + SQL_FetchString(results[0], 0, alias, sizeof(alias)); + + if (SQL_GetRowCount(results[1]) == 0) + { + if (blockType == 0) + { + GOKZ_PrintToChat(client, true, "%T", "Jump Stats Menu - No Jump Stats", client, alias); + } + else + { + GOKZ_PrintToChat(client, true, "%T", "Jump Stats Menu - No Block Jump Stats", client, alias); + } + + DisplayJumpStatsBlockTypeMenu(client, mode); + return; + } + + Menu menu = new Menu(MenuHandler_JumpStatsSubmenu); + if (blockType == 0) + { + menu.SetTitle("%T", "Jump Stats Submenu - Title (Jump)", client, alias, gC_ModeNames[mode]); + } + else + { + menu.SetTitle("%T", "Jump Stats Submenu - Title (Block Jump)", client, alias, gC_ModeNames[mode]); + } + + char buffer[128], admin[64]; + bool clientIsAdmin = CheckCommandAccess(client, "sm_deletejump", ADMFLAG_ROOT, false); + + if (blockType == 0) + { + FormatEx(buffer, sizeof(buffer), "%T", "Jump Stats - Jump Console Header", + client, gC_ModeNames[mode], alias, targetSteamID & 1, targetSteamID >> 1); + PrintToConsole(client, "%s", buffer); + int titleLength = strlen(buffer); + strcopy(buffer, sizeof(buffer), "----------------------------------------------------------------"); + buffer[titleLength] = '\0'; + PrintToConsole(client, "%s", buffer); + + while (SQL_FetchRow(results[1])) + { + int jumpid = SQL_FetchInt(results[1], JumpstatDB_PBMenu_JumpID); + int jumpType = SQL_FetchInt(results[1], JumpstatDB_PBMenu_JumpType); + float distance = SQL_FetchFloat(results[1], JumpstatDB_PBMenu_Distance) / GOKZ_DB_JS_DISTANCE_PRECISION; + int strafes = SQL_FetchInt(results[1], JumpstatDB_PBMenu_Strafes); + float sync = SQL_FetchFloat(results[1], JumpstatDB_PBMenu_Sync) / GOKZ_DB_JS_SYNC_PRECISION; + float pre = SQL_FetchFloat(results[1], JumpstatDB_PBMenu_Pre) / GOKZ_DB_JS_PRE_PRECISION; + float max = SQL_FetchFloat(results[1], JumpstatDB_PBMenu_Max) / GOKZ_DB_JS_MAX_PRECISION; + float airtime = SQL_FetchFloat(results[1], JumpstatDB_PBMenu_Air) / GOKZ_DB_JS_AIRTIME_PRECISION; + + FormatEx(buffer, sizeof(buffer), "%0.4f %s", distance, gC_JumpTypes[jumpType]); + menu.AddItem("", buffer, ITEMDRAW_DISABLED); + + FormatEx(buffer, sizeof(buffer), "%8s", gC_JumpTypesShort[jumpType]); + buffer[3] = '\0'; + + if (clientIsAdmin) + { + FormatEx(admin, sizeof(admin), "", jumpid); + } + + PrintToConsole(client, "%s %0.4f [%d %t | %.2f%% %t | %.2f %t | %.2f %t | %.4f %t] %s", + buffer, distance, strafes, "Strafes", sync, "Sync", pre, "Pre", max, "Max", airtime, "Air", admin); + } + } + else + { + FormatEx(buffer, sizeof(buffer), "%T", "Jump Stats - Block Jump Console Header", + client, gC_ModeNames[mode], alias, targetSteamID & 1, targetSteamID >> 1); + PrintToConsole(client, "%s", buffer); + int titleLength = strlen(buffer); + strcopy(buffer, sizeof(buffer), "----------------------------------------------------------------"); + buffer[titleLength] = '\0'; + PrintToConsole(client, "%s", buffer); + + while (SQL_FetchRow(results[1])) + { + int jumpid = SQL_FetchInt(results[1], JumpstatDB_BlockPBMenu_JumpID); + int jumpType = SQL_FetchInt(results[1], JumpstatDB_BlockPBMenu_JumpType); + int block = SQL_FetchInt(results[1], JumpstatDB_BlockPBMenu_Block); + float distance = SQL_FetchFloat(results[1], JumpstatDB_BlockPBMenu_Distance) / GOKZ_DB_JS_DISTANCE_PRECISION; + int strafes = SQL_FetchInt(results[1], JumpstatDB_BlockPBMenu_Strafes); + float sync = SQL_FetchFloat(results[1], JumpstatDB_BlockPBMenu_Sync) / GOKZ_DB_JS_SYNC_PRECISION; + float pre = SQL_FetchFloat(results[1], JumpstatDB_BlockPBMenu_Pre) / GOKZ_DB_JS_PRE_PRECISION; + float max = SQL_FetchFloat(results[1], JumpstatDB_BlockPBMenu_Max) / GOKZ_DB_JS_MAX_PRECISION; + float airtime = SQL_FetchFloat(results[1], JumpstatDB_BlockPBMenu_Air) / GOKZ_DB_JS_AIRTIME_PRECISION; + + FormatEx(buffer, sizeof(buffer), "%d %T (%0.4f) %s", block, "Block", client, distance, gC_JumpTypes[jumpType]); + menu.AddItem("", buffer, ITEMDRAW_DISABLED); + + FormatEx(buffer, sizeof(buffer), "%8s", gC_JumpTypesShort[jumpType]); + buffer[3] = '\0'; + + if (clientIsAdmin) + { + FormatEx(admin, sizeof(admin), "", jumpid); + } + + PrintToConsole(client, "%s %d %t (%0.4f) [%d %t | %.2f%% %t | %.2f %t | %.2f %t | %.4f %t] %s", + buffer, block, "Block", distance, strafes, "Strafes", sync, "Sync", pre, "Pre", max, "Max", airtime, "Air", admin); + } + } + + PrintToConsole(client, ""); + menu.Display(client, MENU_TIME_FOREVER); +} + + + +// =====[ MENU HANDLERS ]===== + +public int MenuHandler_JumpStatsMode(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + // param1 = client, param2 = mode + DisplayJumpStatsBlockTypeMenu(param1, param2); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_JumpStatsBlockType(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + // param1 = client, param2 = blockType + DB_OpenJumpStats(param1, jumpStatsTargetSteamID[param1], jumpStatsMode[param1], param2); + } + else if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayJumpStatsModeMenu(param1); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_JumpStatsSubmenu(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayJumpStatsBlockTypeMenu(param1, jumpStatsMode[param1]); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/get_completion.sp b/sourcemod/scripting/gokz-localranks/db/get_completion.sp new file mode 100644 index 0000000..fbc76e7 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/get_completion.sp @@ -0,0 +1,155 @@ +/* + Gets the number and percentage of maps completed. +*/ + + + +void DB_GetCompletion(int client, int targetSteamID, int mode, bool print) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(targetSteamID); + data.WriteCell(mode); + data.WriteCell(print); + + Transaction txn = SQL_CreateTransaction(); + + // Retrieve Alias of SteamID + FormatEx(query, sizeof(query), sql_players_getalias, targetSteamID); + txn.AddQuery(query); + // Get total number of ranked main courses + txn.AddQuery(sql_getcount_maincourses); + // Get number of main course completions + FormatEx(query, sizeof(query), sql_getcount_maincoursescompleted, targetSteamID, mode); + txn.AddQuery(query); + // Get number of main course completions (PRO) + FormatEx(query, sizeof(query), sql_getcount_maincoursescompletedpro, targetSteamID, mode); + txn.AddQuery(query); + + // Get total number of ranked bonuses + txn.AddQuery(sql_getcount_bonuses); + // Get number of bonus completions + FormatEx(query, sizeof(query), sql_getcount_bonusescompleted, targetSteamID, mode); + txn.AddQuery(query); + // Get number of bonus completions (PRO) + FormatEx(query, sizeof(query), sql_getcount_bonusescompletedpro, targetSteamID, mode); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_GetCompletion, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_GetCompletion(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int targetSteamID = data.ReadCell(); + int mode = data.ReadCell(); + bool print = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + char playerName[MAX_NAME_LENGTH]; + int totalMainCourses, completions, completionsPro; + int totalBonuses, bonusCompletions, bonusCompletionsPro; + + // Get Player Name from results + if (SQL_FetchRow(results[0])) + { + SQL_FetchString(results[0], 0, playerName, sizeof(playerName)); + } + + // Get total number of main courses + if (SQL_FetchRow(results[1])) + { + totalMainCourses = SQL_FetchInt(results[1], 0); + } + // Get completed main courses + if (SQL_FetchRow(results[2])) + { + completions = SQL_FetchInt(results[2], 0); + } + // Get completed main courses (PRO) + if (SQL_FetchRow(results[3])) + { + completionsPro = SQL_FetchInt(results[3], 0); + } + + // Get total number of bonuses + if (SQL_FetchRow(results[4])) + { + totalBonuses = SQL_FetchInt(results[4], 0); + } + // Get completed bonuses + if (SQL_FetchRow(results[5])) { + bonusCompletions = SQL_FetchInt(results[5], 0); + } + // Get completed bonuses (PRO) + if (SQL_FetchRow(results[6])) + { + bonusCompletionsPro = SQL_FetchInt(results[6], 0); + } + + // Print completion message to chat if specified + if (print) + { + if (totalMainCourses + totalBonuses == 0) + { + GOKZ_PrintToChat(client, true, "%t", "No Ranked Maps"); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Map Completion", + playerName, + completions, totalMainCourses, completionsPro, totalMainCourses, + bonusCompletions, totalBonuses, bonusCompletionsPro, totalBonuses, + gC_ModeNamesShort[mode]); + } + } + + // Set scoreboard MVP stars to percentage PRO completion of server's default mode + if (totalMainCourses + totalBonuses != 0 && targetSteamID == GetSteamAccountID(client) && mode == GOKZ_GetDefaultMode()) + { + CS_SetMVPCount(client, RoundToFloor(float(completionsPro + bonusCompletionsPro) / float(totalMainCourses + totalBonuses) * 100.0)); + } +} + +void DB_GetCompletion_FindPlayer(int client, const char[] target, int mode) +{ + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteString(target); + data.WriteCell(mode); + + DB_FindPlayer(target, DB_TxnSuccess_GetCompletion_FindPlayer, data, DBPrio_Low); +} + +public void DB_TxnSuccess_GetCompletion_FindPlayer(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + char playerSearch[33]; + data.ReadString(playerSearch, sizeof(playerSearch)); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + else if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Player Not Found", playerSearch); + return; + } + else if (SQL_FetchRow(results[0])) + { + DB_GetCompletion(client, SQL_FetchInt(results[0], 0), mode, true); + } +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/helpers.sp b/sourcemod/scripting/gokz-localranks/db/helpers.sp new file mode 100644 index 0000000..670a420 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/helpers.sp @@ -0,0 +1,91 @@ +/* + Database helper functions and callbacks. +*/ + + + +/* Error report callback for failed transactions */ +public void DB_TxnFailure_Generic(Handle db, any data, int numQueries, const char[] error, int failIndex, any[] queryData) +{ + LogError("Database transaction error: %s", error); +} + +/* Error report callback for failed transactions which deletes the DataPack */ +public void DB_TxnFailure_Generic_DataPack(Handle db, DataPack data, int numQueries, const char[] error, int failIndex, any[] queryData) +{ + delete data; + LogError("Database transaction error: %s", error); +} + +/* Used to search the database for a player name and return their PlayerID and alias + + For SQLTxnSuccess onSuccess: + results[0] - 0:PlayerID, 1:Alias +*/ +void DB_FindPlayer(const char[] playerSearch, SQLTxnSuccess onSuccess, any data = 0, DBPriority priority = DBPrio_Normal) +{ + char query[1024], playerEscaped[MAX_NAME_LENGTH * 2 + 1]; + SQL_EscapeString(gH_DB, playerSearch, playerEscaped, sizeof(playerEscaped)); + + String_ToLower(playerEscaped, playerEscaped, sizeof(playerEscaped)); + + Transaction txn = SQL_CreateTransaction(); + + // Look for player name and retrieve their PlayerID + FormatEx(query, sizeof(query), sql_players_searchbyalias, playerEscaped, playerEscaped); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, onSuccess, DB_TxnFailure_Generic, data, priority); +} + +/* Used to search the database for a map name and return its MapID and name + + For SQLTxnSuccess onSuccess: + results[0] - 0:MapID, 1:Name +*/ +void DB_FindMap(const char[] mapSearch, SQLTxnSuccess onSuccess, any data = 0, DBPriority priority = DBPrio_Normal) +{ + char query[1024], mapEscaped[129]; + SQL_EscapeString(gH_DB, mapSearch, mapEscaped, sizeof(mapEscaped)); + + Transaction txn = SQL_CreateTransaction(); + + // Look for map name and retrieve it's MapID + FormatEx(query, sizeof(query), sql_maps_searchbyname, mapEscaped, mapEscaped); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, onSuccess, DB_TxnFailure_Generic, data, priority); +} + +/* Used to search the database for a player name and return their PlayerID and alias, + and search the database for a map name and return its MapID and name + + For SQLTxnSuccess onSuccess: + results[0] - 0:PlayerID, 1:Alias + results[1] - 0:MapID, 1:Name +*/ +void DB_FindPlayerAndMap(const char[] playerSearch, const char[] mapSearch, SQLTxnSuccess onSuccess, any data = 0, DBPriority priority = DBPrio_Normal) +{ + char query[1024], mapEscaped[129], playerEscaped[MAX_NAME_LENGTH * 2 + 1]; + SQL_EscapeString(gH_DB, playerSearch, playerEscaped, sizeof(playerEscaped)); + SQL_EscapeString(gH_DB, mapSearch, mapEscaped, sizeof(mapEscaped)); + + String_ToLower(playerEscaped, playerEscaped, sizeof(playerEscaped)); + + Transaction txn = SQL_CreateTransaction(); + + // Look for player name and retrieve their PlayerID + FormatEx(query, sizeof(query), sql_players_searchbyalias, playerEscaped, playerEscaped); + txn.AddQuery(query); + // Look for map name and retrieve it's MapID + FormatEx(query, sizeof(query), sql_maps_searchbyname, mapEscaped, mapEscaped); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, onSuccess, DB_TxnFailure_Generic, data, priority); +} + +// Used to convert the Account ID to the SteamID we can use for a Global API query +int GetSteam2FromAccountId(char[] result, int maxlen, int account_id) +{ + return Format(result, maxlen, "STEAM_1:%d:%d", view_as(account_id % 2), account_id / 2); +} diff --git a/sourcemod/scripting/gokz-localranks/db/js_top.sp b/sourcemod/scripting/gokz-localranks/db/js_top.sp new file mode 100644 index 0000000..a336a90 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/js_top.sp @@ -0,0 +1,286 @@ + +static int jumpTopMode[MAXPLAYERS + 1]; +static int jumpTopType[MAXPLAYERS + 1]; +static int blockNums[MAXPLAYERS + 1][JS_TOP_RECORD_COUNT]; +static int jumpInfo[MAXPLAYERS + 1][JS_TOP_RECORD_COUNT][3]; + + + +void DB_OpenJumpTop(int client, int mode, int jumpType, int blockType) +{ + char query[1024]; + + Transaction txn = SQL_CreateTransaction(); + + FormatEx(query, sizeof(query), sql_jumpstats_gettop, jumpType, mode, blockType, jumpType, mode, blockType, JS_TOP_RECORD_COUNT); + txn.AddQuery(query); + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(mode); + data.WriteCell(jumpType); + data.WriteCell(blockType); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_GetJumpTop, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +void DB_TxnSuccess_GetJumpTop(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int mode = data.ReadCell(); + int type = data.ReadCell(); + int blockType = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + jumpTopMode[client] = mode; + jumpTopType[client] = type; + + int rows = SQL_GetRowCount(results[0]); + if (rows == 0) + { + GOKZ_PrintToChat(client, true, "%t", "No Jumpstats Found"); + DisplayJumpTopBlockTypeMenu(client, mode, type); + return; + } + + char display[128], alias[33], title[65], admin[65]; + int jumpid, steamid, block, strafes; + float distance, sync, pre, max, airtime; + + bool clientIsAdmin = CheckCommandAccess(client, "sm_deletejump", ADMFLAG_ROOT, false); + + Menu menu = new Menu(MenuHandler_JumpTopList); + menu.Pagination = 5; + + if (blockType == 0) + { + menu.SetTitle("%T", "Jump Top Submenu - Title (Jump)", client, gC_ModeNames[mode], gC_JumpTypes[type]); + + FormatEx(title, sizeof(title), "%s %s %T", gC_ModeNames[mode], gC_JumpTypes[type], "Top", client); + strcopy(display, sizeof(display), "----------------------------------------------------------------"); + display[strlen(title)] = '\0'; + + PrintToConsole(client, title); + PrintToConsole(client, display); + + for (int i = 0; i < rows; i++) + { + SQL_FetchRow(results[0]); + jumpid = SQL_FetchInt(results[0], JumpstatDB_Top20_JumpID); + steamid = SQL_FetchInt(results[0], JumpstatDB_Top20_SteamID); + SQL_FetchString(results[0], JumpstatDB_Top20_Alias, alias, sizeof(alias)); + distance = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Distance)) / GOKZ_DB_JS_DISTANCE_PRECISION; + strafes = SQL_FetchInt(results[0], JumpstatDB_Top20_Strafes); + sync = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Sync)) / GOKZ_DB_JS_SYNC_PRECISION; + pre = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Pre)) / GOKZ_DB_JS_PRE_PRECISION; + max = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Max)) / GOKZ_DB_JS_MAX_PRECISION; + airtime = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Air)) / GOKZ_DB_JS_AIRTIME_PRECISION; + + FormatEx(display, sizeof(display), "#%-2d %.4f %s", i + 1, distance, alias); + + menu.AddItem(IntToStringEx(i), display); + + if (clientIsAdmin) + { + FormatEx(admin, sizeof(admin), "", jumpid); + } + + PrintToConsole(client, "#%-2d %.4f %s [%d %t | %.2f%% %t | %.2f %t | %.2f %t | %.4f %t] %s", + i + 1, distance, alias, steamid & 1, steamid >> 1, + strafes, "Strafes", sync, "Sync", pre, "Pre", max, "Max", airtime, "Air", + admin); + + jumpInfo[client][i][0] = steamid; + jumpInfo[client][i][1] = type; + jumpInfo[client][i][2] = mode; + blockNums[client][i] = 0; + } + } + else + { + menu.SetTitle("%T", "Jump Top Submenu - Title (Block Jump)", client, gC_ModeNames[mode], gC_JumpTypes[type]); + + FormatEx(title, sizeof(title), "%s %T %s %T", gC_ModeNames[mode], "Block", client, gC_JumpTypes[type], "Top", client); + strcopy(display, sizeof(display), "----------------------------------------------------------------"); + display[strlen(title)] = '\0'; + + PrintToConsole(client, title); + PrintToConsole(client, display); + + for (int i = 0; i < rows; i++) + { + SQL_FetchRow(results[0]); + jumpid = SQL_FetchInt(results[0], JumpstatDB_Top20_JumpID); + steamid = SQL_FetchInt(results[0], JumpstatDB_Top20_SteamID); + SQL_FetchString(results[0], JumpstatDB_Top20_Alias, alias, sizeof(alias)); + block = SQL_FetchInt(results[0], JumpstatDB_Top20_Block); + distance = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Distance)) / GOKZ_DB_JS_DISTANCE_PRECISION; + strafes = SQL_FetchInt(results[0], JumpstatDB_Top20_Strafes); + sync = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Sync)) / GOKZ_DB_JS_SYNC_PRECISION; + pre = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Pre)) / GOKZ_DB_JS_PRE_PRECISION; + max = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Max)) / GOKZ_DB_JS_MAX_PRECISION; + airtime = float(SQL_FetchInt(results[0], JumpstatDB_Top20_Air)) / GOKZ_DB_JS_AIRTIME_PRECISION; + + FormatEx(display, sizeof(display), "#%-2d %d %T (%.4f) %s", i + 1, block, "Block", client, distance, alias); + menu.AddItem(IntToStringEx(i), display); + + if (clientIsAdmin) + { + FormatEx(admin, sizeof(admin), "", jumpid); + } + + PrintToConsole(client, "#%-2d %d %t (%.4f) %s [%d %t | %.2f%% %t | %.2f %t | %.2f %t | %.4f %t] %s", + i + 1, block, "Block", distance, alias, steamid & 1, steamid >> 1, + strafes, "Strafes", sync, "Sync", pre, "Pre", max, "Max", airtime, "Air", + admin); + + jumpInfo[client][i][0] = steamid; + jumpInfo[client][i][1] = type; + jumpInfo[client][i][2] = mode; + blockNums[client][i] = block; + } + } + menu.Display(client, MENU_TIME_FOREVER); + PrintToConsole(client, ""); +} + +// =====[ MENUS ]===== + +void DisplayJumpTopModeMenu(int client) +{ + Menu menu = new Menu(MenuHandler_JumpTopMode); + menu.SetTitle("%T", "Jump Top Mode Menu - Title", client); + GOKZ_MenuAddModeItems(client, menu, false); + menu.Display(client, MENU_TIME_FOREVER); +} + +void DisplayJumpTopTypeMenu(int client, int mode) +{ + jumpTopMode[client] = mode; + + Menu menu = new Menu(MenuHandler_JumpTopType); + menu.SetTitle("%T", "Jump Top Type Menu - Title", client, gC_ModeNames[jumpTopMode[client]]); + JumpTopTypeMenuAddItems(menu); + menu.Display(client, MENU_TIME_FOREVER); +} + +static void JumpTopTypeMenuAddItems(Menu menu) +{ + char display[32]; + for (int i = 0; i < JUMPTYPE_COUNT - 3; i++) + { + FormatEx(display, sizeof(display), "%s", gC_JumpTypes[i]); + menu.AddItem(IntToStringEx(i), display); + } +} + +void DisplayJumpTopBlockTypeMenu(int client, int mode, int type) +{ + jumpTopMode[client] = mode; + jumpTopType[client] = type; + + Menu menu = new Menu(MenuHandler_JumpTopBlockType); + menu.SetTitle("%T", "Jump Top Block Type Menu - Title", client, gC_ModeNames[jumpTopMode[client]], gC_JumpTypes[jumpTopType[client]]); + JumpTopBlockTypeMenuAddItems(client, menu); + menu.Display(client, MENU_TIME_FOREVER); +} + +static void JumpTopBlockTypeMenuAddItems(int client, Menu menu) +{ + char str[64]; + FormatEx(str, sizeof(str), "%T", "Jump Records", client); + menu.AddItem("jump", str); + FormatEx(str, sizeof(str), "%T %T", "Block", client, "Jump Records", client); + menu.AddItem("blockjump", str); +} + + + +// =====[ MENU HANDLERS ]===== + +public int MenuHandler_JumpTopMode(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + // param1 = client, param2 = mode + DisplayJumpTopTypeMenu(param1, param2); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_JumpTopType(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + // param1 = client, param2 = type + DisplayJumpTopBlockTypeMenu(param1, jumpTopMode[param1], param2); + } + else if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayJumpTopModeMenu(param1); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_JumpTopBlockType(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + // param1 = client, param2 = block type + DB_OpenJumpTop(param1, jumpTopMode[param1], jumpTopType[param1], param2); + } + else if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayJumpTopTypeMenu(param1, jumpTopMode[param1]); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_JumpTopList(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + char path[PLATFORM_MAX_PATH]; + if (blockNums[param1][param2] == 0) + { + BuildPath(Path_SM, path, sizeof(path), + "%s/%d/%d_%s_%s.%s", + RP_DIRECTORY_JUMPS, jumpInfo[param1][param2][0], jumpTopType[param1], gC_ModeNamesShort[jumpInfo[param1][param2][2]], gC_StyleNamesShort[0], RP_FILE_EXTENSION); + } + else + { + BuildPath(Path_SM, path, sizeof(path), + "%s/%d/%s/%d_%d_%s_%s.%s", + RP_DIRECTORY_JUMPS, jumpInfo[param1][param2][0], RP_DIRECTORY_BLOCKJUMPS, jumpTopType[param1], blockNums[param1][param2], gC_ModeNamesShort[jumpInfo[param1][param2][2]], gC_StyleNamesShort[0], RP_FILE_EXTENSION); + } + GOKZ_RP_LoadJumpReplay(param1, path); + } + + if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayJumpTopBlockTypeMenu(param1, jumpTopMode[param1], jumpTopType[param1]); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} diff --git a/sourcemod/scripting/gokz-localranks/db/map_top.sp b/sourcemod/scripting/gokz-localranks/db/map_top.sp new file mode 100644 index 0000000..5b296e9 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/map_top.sp @@ -0,0 +1,388 @@ +/* + Opens a menu with the top times for a map course and mode. +*/ + + + +#define ITEM_INFO_GLOBAL_TOP_NUB "gn" +#define ITEM_INFO_GLOBAL_TOP_PRO "gp" + +static char mapTopMap[MAXPLAYERS + 1][64]; +static int mapTopMapID[MAXPLAYERS + 1]; +static int mapTopCourse[MAXPLAYERS + 1]; +static int mapTopMode[MAXPLAYERS + 1]; + + + +// =====[ MAP TOP MODE ]===== + +void DB_OpenMapTopModeMenu(int client, int mapID, int course) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(mapID); + data.WriteCell(course); + + Transaction txn = SQL_CreateTransaction(); + + // Retrieve Map Name of MapID + FormatEx(query, sizeof(query), sql_maps_getname, mapID); + txn.AddQuery(query); + // Check for existence of map course with that MapID and Course + FormatEx(query, sizeof(query), sql_mapcourses_findid, mapID, course); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_OpenMapTopModeMenu, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_OpenMapTopModeMenu(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int mapID = data.ReadCell(); + int course = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + // Get name of map + if (SQL_FetchRow(results[0])) + { + SQL_FetchString(results[0], 0, mapTopMap[client], sizeof(mapTopMap[])); + } + // Check if the map course exists in the database + if (SQL_GetRowCount(results[1]) == 0) + { + if (course == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Main Course Not Found", mapTopMap[client]); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Bonus Not Found", mapTopMap[client], course); + } + return; + } + + mapTopMapID[client] = mapID; + mapTopCourse[client] = course; + DisplayMapTopModeMenu(client); +} + +void DB_OpenMapTopModeMenu_FindMap(int client, const char[] mapSearch, int course) +{ + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteString(mapSearch); + data.WriteCell(course); + + DB_FindMap(mapSearch, DB_TxnSuccess_OpenMapTopModeMenu_FindMap, data, DBPrio_Low); +} + +public void DB_TxnSuccess_OpenMapTopModeMenu_FindMap(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + char mapSearch[33]; + data.ReadString(mapSearch, sizeof(mapSearch)); + int course = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Map Not Found", mapSearch); + return; + } + else if (SQL_FetchRow(results[0])) + { // Result is the MapID + DB_OpenMapTopModeMenu(client, SQL_FetchInt(results[0], 0), course); + } +} + + + +// =====[ MAP TOP ]===== + +void DB_OpenMapTop(int client, int mapID, int course, int mode, int timeType) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(course); + data.WriteCell(mode); + data.WriteCell(timeType); + + Transaction txn = SQL_CreateTransaction(); + + // Get map name + FormatEx(query, sizeof(query), sql_maps_getname, mapID); + txn.AddQuery(query); + // Check for existence of map course with that MapID and Course + FormatEx(query, sizeof(query), sql_mapcourses_findid, mapID, course); + txn.AddQuery(query); + + // Get top times for each time type + switch (timeType) + { + case TimeType_Nub:FormatEx(query, sizeof(query), sql_getmaptop, mapID, course, mode, LR_MAP_TOP_CUTOFF); + case TimeType_Pro:FormatEx(query, sizeof(query), sql_getmaptoppro, mapID, course, mode, LR_MAP_TOP_CUTOFF); + } + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_OpenMapTop, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_OpenMapTop(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int course = data.ReadCell(); + int mode = data.ReadCell(); + int timeType = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + // Get map name from results + char mapName[64]; + if (SQL_FetchRow(results[0])) + { + SQL_FetchString(results[0], 0, mapName, sizeof(mapName)); + } + // Check if the map course exists in the database + if (SQL_GetRowCount(results[1]) == 0) + { + if (course == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Main Course Not Found", mapName); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Bonus Not Found", mapName, course); + } + return; + } + + // Check if there are any times + if (SQL_GetRowCount(results[2]) == 0) + { + switch (timeType) + { + case TimeType_Nub:GOKZ_PrintToChat(client, true, "%t", "No Times Found"); + case TimeType_Pro:GOKZ_PrintToChat(client, true, "%t", "No Times Found (PRO)"); + } + DisplayMapTopMenu(client, mode); + return; + } + + Menu menu = new Menu(MenuHandler_MapTopSubmenu); + menu.Pagination = 5; + + // Set submenu title + if (course == 0) + { + menu.SetTitle("%T", "Map Top Submenu - Title", client, + LR_MAP_TOP_CUTOFF, gC_TimeTypeNames[timeType], mapName, gC_ModeNames[mode]); + } + else + { + menu.SetTitle("%T", "Map Top Submenu - Title (Bonus)", client, + LR_MAP_TOP_CUTOFF, gC_TimeTypeNames[timeType], mapName, course, gC_ModeNames[mode]); + } + + // Add submenu items + char display[128], title[65], admin[65]; + char playerName[MAX_NAME_LENGTH]; + float runTime; + int timeid, steamid, teleports, rank = 0; + + bool clientIsAdmin = CheckCommandAccess(client, "sm_deletetime", ADMFLAG_ROOT, false); + + FormatEx(title, sizeof(title), "%s %s %s %T", gC_ModeNames[mode], mapName, gC_TimeTypeNames[timeType], "Top", client); + strcopy(display, sizeof(display), "----------------------------------------------------------------"); + display[strlen(title)] = '\0'; + PrintToConsole(client, title); + PrintToConsole(client, display); + + while (SQL_FetchRow(results[2])) + { + rank++; + timeid = SQL_FetchInt(results[2], 0); + steamid = SQL_FetchInt(results[2], 1); + SQL_FetchString(results[2], 2, playerName, sizeof(playerName)); + runTime = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[2], 3)); + + if (clientIsAdmin) + { + FormatEx(admin, sizeof(admin), "", timeid); + } + + switch (timeType) + { + case TimeType_Nub: + { + teleports = SQL_FetchInt(results[2], 4); + FormatEx(display, sizeof(display), "#%-2d %11s %3d TP %s", + rank, GOKZ_FormatTime(runTime), teleports, playerName); + + PrintToConsole(client, "#%-2d %11s %3d TP %s %s", + rank, GOKZ_FormatTime(runTime), teleports, playerName, steamid & 1, steamid >> 1, admin); + } + case TimeType_Pro: + { + FormatEx(display, sizeof(display), "#%-2d %11s %s", + rank, GOKZ_FormatTime(runTime), playerName); + + PrintToConsole(client, "#%-2d %11s %s %s", + rank, GOKZ_FormatTime(runTime), playerName, steamid & 1, steamid >> 1, admin); + } + } + menu.AddItem("", display, ITEMDRAW_DISABLED); + } + + menu.Display(client, MENU_TIME_FOREVER); +} + + + +// =====[ MENUS ]===== + +void DisplayMapTopModeMenu(int client) +{ + Menu menu = new Menu(MenuHandler_MapTopMode); + MapTopModeMenuSetTitle(client, menu); + GOKZ_MenuAddModeItems(client, menu, false); + menu.Display(client, MENU_TIME_FOREVER); +} + +static void MapTopModeMenuSetTitle(int client, Menu menu) +{ + if (mapTopCourse[client] == 0) + { + menu.SetTitle("%T", "Map Top Mode Menu - Title", client, mapTopMap[client]); + } + else + { + menu.SetTitle("%T", "Map Top Mode Menu - Title (Bonus)", client, mapTopMap[client], mapTopCourse[client]); + } +} + +void DisplayMapTopMenu(int client, int mode) +{ + mapTopMode[client] = mode; + + Menu menu = new Menu(MenuHandler_MapTop); + if (mapTopCourse[client] == 0) + { + menu.SetTitle("%T", "Map Top Menu - Title", client, + mapTopMap[client], gC_ModeNames[mapTopMode[client]]); + } + else + { + menu.SetTitle("%T", "Map Top Menu - Title (Bonus)", client, + mapTopMap[client], mapTopCourse[client], gC_ModeNames[mapTopMode[client]]); + } + MapTopMenuAddItems(client, menu); + menu.Display(client, MENU_TIME_FOREVER); +} + +static void MapTopMenuAddItems(int client, Menu menu) +{ + char display[32]; + for (int i = 0; i < TIMETYPE_COUNT; i++) + { + FormatEx(display, sizeof(display), "%T", "Map Top Menu - Top", client, LR_MAP_TOP_CUTOFF, gC_TimeTypeNames[i]); + menu.AddItem(IntToStringEx(i), display); + } + if (gB_GOKZGlobal) + { + FormatEx(display, sizeof(display), "%T", "Map Top Menu - Global Top", client, gC_TimeTypeNames[TimeType_Nub]); + menu.AddItem(ITEM_INFO_GLOBAL_TOP_NUB, display); + + FormatEx(display, sizeof(display), "%T", "Map Top Menu - Global Top", client, gC_TimeTypeNames[TimeType_Pro]); + menu.AddItem(ITEM_INFO_GLOBAL_TOP_PRO, display); + } +} + +void ReopenMapTopMenu(int client) +{ + DisplayMapTopMenu(client, mapTopMode[client]); +} + + + +// =====[ MENU HANDLERS ]===== + +public int MenuHandler_MapTopMode(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + // param1 = client, param2 = mode + DisplayMapTopMenu(param1, param2); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_MapTop(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + char info[8]; + menu.GetItem(param2, info, sizeof(info)); + + if (gB_GOKZGlobal && StrEqual(info, ITEM_INFO_GLOBAL_TOP_NUB)) + { + GOKZ_GL_DisplayMapTopMenu(param1, mapTopMap[param1], mapTopCourse[param1], mapTopMode[param1], TimeType_Nub); + } + else if (gB_GOKZGlobal && StrEqual(info, ITEM_INFO_GLOBAL_TOP_PRO)) + { + GOKZ_GL_DisplayMapTopMenu(param1, mapTopMap[param1], mapTopCourse[param1], mapTopMode[param1], TimeType_Pro); + } + else + { + int timeType = StringToInt(info); + DB_OpenMapTop(param1, mapTopMapID[param1], mapTopCourse[param1], mapTopMode[param1], timeType); + } + } + else if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayMapTopModeMenu(param1); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_MapTopSubmenu(Menu menu, MenuAction action, int param1, int param2) +{ + // TODO Menu item info is player's SteamID32, but is currently not used + if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + ReopenMapTopMenu(param1); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/player_top.sp b/sourcemod/scripting/gokz-localranks/db/player_top.sp new file mode 100644 index 0000000..0348eec --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/player_top.sp @@ -0,0 +1,165 @@ +/* + Opens a menu with top record holders of a time type and mode. +*/ + + + +static int playerTopMode[MAXPLAYERS + 1]; + + + +void DB_OpenPlayerTop(int client, int timeType, int mode) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(timeType); + data.WriteCell(mode); + + Transaction txn = SQL_CreateTransaction(); + + // Get top players + switch (timeType) + { + case TimeType_Nub: + { + FormatEx(query, sizeof(query), sql_gettopplayers, mode, LR_PLAYER_TOP_CUTOFF); + txn.AddQuery(query); + } + case TimeType_Pro: + { + FormatEx(query, sizeof(query), sql_gettopplayerspro, mode, LR_PLAYER_TOP_CUTOFF); + txn.AddQuery(query); + } + } + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_OpenPlayerTop, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_OpenPlayerTop(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int timeType = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + if (SQL_GetRowCount(results[0]) == 0) + { + switch (timeType) + { + case TimeType_Nub:GOKZ_PrintToChat(client, true, "%t", "Player Top - No Times"); + case TimeType_Pro:GOKZ_PrintToChat(client, true, "%t", "Player Top - No Times (PRO)"); + } + DisplayPlayerTopMenu(client, playerTopMode[client]); + return; + } + + Menu menu = new Menu(MenuHandler_PlayerTopSubmenu); + menu.Pagination = 5; + + // Set submenu title + menu.SetTitle("%T", "Player Top Submenu - Title", client, + LR_PLAYER_TOP_CUTOFF, gC_TimeTypeNames[timeType], gC_ModeNames[mode]); + + // Add submenu items + char display[256]; + int rank = 0; + while (SQL_FetchRow(results[0])) + { + rank++; + char playerString[33]; + SQL_FetchString(results[0], 1, playerString, sizeof(playerString)); + FormatEx(display, sizeof(display), "#%-2d %s (%d)", rank, playerString, SQL_FetchInt(results[0], 2)); + menu.AddItem(IntToStringEx(SQL_FetchInt(results[0], 0)), display, ITEMDRAW_DISABLED); + } + + menu.Display(client, MENU_TIME_FOREVER); +} + + + +// =====[ MENUS ]===== + +void DisplayPlayerTopModeMenu(int client) +{ + Menu menu = new Menu(MenuHandler_PlayerTopMode); + menu.SetTitle("%T", "Player Top Mode Menu - Title", client); + GOKZ_MenuAddModeItems(client, menu, false); + menu.Display(client, MENU_TIME_FOREVER); +} + +void DisplayPlayerTopMenu(int client, int mode) +{ + playerTopMode[client] = mode; + + Menu menu = new Menu(MenuHandler_PlayerTop); + menu.SetTitle("%T", "Player Top Menu - Title", client, gC_ModeNames[mode]); + PlayerTopMenuAddItems(client, menu); + menu.Display(client, MENU_TIME_FOREVER); +} + +static void PlayerTopMenuAddItems(int client, Menu menu) +{ + char display[32]; + for (int timeType = 0; timeType < TIMETYPE_COUNT; timeType++) + { + FormatEx(display, sizeof(display), "%T", "Player Top Menu - Top", client, + LR_PLAYER_TOP_CUTOFF, gC_TimeTypeNames[timeType]); + menu.AddItem("", display, ITEMDRAW_DEFAULT); + } +} + + + +// =====[ MENU HANLDERS ]===== + +public int MenuHandler_PlayerTopMode(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + DisplayPlayerTopMenu(param1, param2); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_PlayerTop(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + DB_OpenPlayerTop(param1, param2, playerTopMode[param1]); + } + else if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayPlayerTopModeMenu(param1); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_PlayerTopSubmenu(Menu menu, MenuAction action, int param1, int param2) +{ + // Menu item info is player's SteamID32, but is currently not used + if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayPlayerTopMenu(param1, playerTopMode[param1]); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/print_average.sp b/sourcemod/scripting/gokz-localranks/db/print_average.sp new file mode 100644 index 0000000..7f7c4e4 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/print_average.sp @@ -0,0 +1,152 @@ +/* + Gets the average personal best time of a course. +*/ + + + +void DB_PrintAverage(int client, int mapID, int course, int mode) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(course); + data.WriteCell(mode); + + Transaction txn = SQL_CreateTransaction(); + + // Retrieve Map Name of MapID + FormatEx(query, sizeof(query), sql_maps_getname, mapID); + txn.AddQuery(query); + // Check for existence of map course with that MapID and Course + FormatEx(query, sizeof(query), sql_mapcourses_findid, mapID, course); + txn.AddQuery(query); + // Get Average PB Time + FormatEx(query, sizeof(query), sql_getaverage, mapID, course, mode); + txn.AddQuery(query); + // Get Average PRO PB Time + FormatEx(query, sizeof(query), sql_getaverage_pro, mapID, course, mode); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_PrintAverage, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_PrintAverage(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int course = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + char mapName[33]; + int mapCompletions, mapCompletionsPro; + float averageTime, averageTimePro; + + // Get Map Name from results + if (SQL_FetchRow(results[0])) + { + SQL_FetchString(results[0], 0, mapName, sizeof(mapName)); + } + if (SQL_GetRowCount(results[1]) == 0) + { + if (course == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Main Course Not Found", mapName); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Bonus Not Found", mapName, course); + } + return; + } + + // Get number of completions and average time + if (SQL_FetchRow(results[2])) + { + mapCompletions = SQL_FetchInt(results[2], 1); + if (mapCompletions > 0) + { + averageTime = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[2], 0)); + } + } + + // Get number of completions and average time (PRO) + if (SQL_FetchRow(results[3])) + { + mapCompletionsPro = SQL_FetchInt(results[3], 1); + if (mapCompletions > 0) + { + averageTimePro = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[3], 0)); + } + } + + // Print average time header to chat + if (course == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Average Time Header", mapName, gC_ModeNamesShort[mode]); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Average Time Header (Bonus)", mapName, course, gC_ModeNamesShort[mode]); + } + + if (mapCompletions == 0) + { + CPrintToChat(client, "%t", "No Times Found"); + } + else if (mapCompletionsPro == 0) + { + CPrintToChat(client, "%t, %t", + "Average Time - NUB", GOKZ_FormatTime(averageTime), mapCompletions, + "Average Time - No PRO Time"); + } + else + { + CPrintToChat(client, "%t, %t", + "Average Time - NUB", GOKZ_FormatTime(averageTime), mapCompletions, + "Average Time - PRO", GOKZ_FormatTime(averageTimePro), mapCompletionsPro); + } +} + +void DB_PrintAverage_FindMap(int client, const char[] mapSearch, int course, int mode) +{ + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteString(mapSearch); + data.WriteCell(course); + data.WriteCell(mode); + + DB_FindMap(mapSearch, DB_TxnSuccess_PrintAverage_FindMap, data, DBPrio_Low); +} + +public void DB_TxnSuccess_PrintAverage_FindMap(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + char mapSearch[33]; + data.ReadString(mapSearch, sizeof(mapSearch)); + int course = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Map Not Found", mapSearch); + return; + } + else if (SQL_FetchRow(results[0])) + { // Result is the MapID + DB_PrintAverage(client, SQL_FetchInt(results[0], 0), course, mode); + } +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/print_js.sp b/sourcemod/scripting/gokz-localranks/db/print_js.sp new file mode 100644 index 0000000..e694a95 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/print_js.sp @@ -0,0 +1,108 @@ +/* + Prints the player's personal best jumps. +*/ + + + +void DisplayJumpstatRecord(int client, int jumpType, char[] jumper = "") +{ + int mode = GOKZ_GetCoreOption(client, Option_Mode); + + int steamid; + char alias[33]; + if (StrEqual(jumper, "")) + { + steamid = GetSteamAccountID(client); + FormatEx(alias, sizeof(alias), "%N", client); + + DB_JS_OpenPlayerRecord(client, steamid, alias, jumpType, mode, 0); + DB_JS_OpenPlayerRecord(client, steamid, alias, jumpType, mode, 1); + } + else + { + DataPack data = new DataPack(); + data.WriteCell(client); + data.WriteCell(jumpType); + data.WriteCell(mode); + data.WriteString(jumper); + + DB_FindPlayer(jumper, DB_JS_TxnSuccess_LookupPlayer, data); + } +} + +public void DB_JS_TxnSuccess_LookupPlayer(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + char jumper[MAX_NAME_LENGTH]; + + data.Reset(); + int client = data.ReadCell(); + int jumpType = data.ReadCell(); + int mode = data.ReadCell(); + data.ReadString(jumper, sizeof(jumper)); + delete data; + + if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Player Not Found", jumper); + return; + } + + char alias[33]; + SQL_FetchRow(results[0]); + int steamid = SQL_FetchInt(results[0], JumpstatDB_FindPlayer_SteamID32); + SQL_FetchString(results[0], JumpstatDB_FindPlayer_Alias, alias, sizeof(alias)); + + DB_JS_OpenPlayerRecord(client, steamid, alias, jumpType, mode, 0); + DB_JS_OpenPlayerRecord(client, steamid, alias, jumpType, mode, 1); +} + +void DB_JS_OpenPlayerRecord(int client, int steamid, char[] alias, int jumpType, int mode, int block) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(client); + data.WriteString(alias); + data.WriteCell(jumpType); + data.WriteCell(mode); + + Transaction txn = SQL_CreateTransaction(); + FormatEx(query, sizeof(query), sql_jumpstats_getrecord, steamid, jumpType, mode, block); + txn.AddQuery(query); + SQL_ExecuteTransaction(gH_DB, txn, DB_JS_TxnSuccess_OpenPlayerRecord, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_JS_TxnSuccess_OpenPlayerRecord(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + char alias[33]; + data.Reset(); + int client = data.ReadCell(); + data.ReadString(alias, sizeof(alias)); + int jumpType = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "No Jumpstats Found"); + return; + } + + SQL_FetchRow(results[0]); + float distance = float(SQL_FetchInt(results[0], JumpstatDB_Lookup_Distance)) / 10000; + int block = SQL_FetchInt(results[0], JumpstatDB_Lookup_Block); + + if (block == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Jump Record", gC_ModeNamesShort[mode], gC_JumpTypes[jumpType], alias, distance); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Block Jump Record", gC_ModeNamesShort[mode], gC_JumpTypes[jumpType], alias, block, distance); + } +} diff --git a/sourcemod/scripting/gokz-localranks/db/print_pbs.sp b/sourcemod/scripting/gokz-localranks/db/print_pbs.sp new file mode 100644 index 0000000..0d541d4 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/print_pbs.sp @@ -0,0 +1,266 @@ +/* + Prints the player's personal times on a map course and given mode. +*/ + + + +void DB_PrintPBs(int client, int targetSteamID, int mapID, int course, int mode) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(course); + data.WriteCell(mode); + + Transaction txn = SQL_CreateTransaction(); + + // Retrieve Alias of SteamID + FormatEx(query, sizeof(query), sql_players_getalias, targetSteamID); + txn.AddQuery(query); + // Retrieve Map Name of MapID + FormatEx(query, sizeof(query), sql_maps_getname, mapID); + txn.AddQuery(query); + // Check for existence of map course with that MapID and Course + FormatEx(query, sizeof(query), sql_mapcourses_findid, mapID, course); + txn.AddQuery(query); + + // Get PB + FormatEx(query, sizeof(query), sql_getpb, targetSteamID, mapID, course, mode, 1); + txn.AddQuery(query); + // Get Rank + FormatEx(query, sizeof(query), sql_getmaprank, mapID, course, mode, targetSteamID, mapID, course, mode); + txn.AddQuery(query); + // Get Number of Players with Times + FormatEx(query, sizeof(query), sql_getlowestmaprank, mapID, course, mode); + txn.AddQuery(query); + + // Get PRO PB + FormatEx(query, sizeof(query), sql_getpbpro, targetSteamID, mapID, course, mode, 1); + txn.AddQuery(query); + // Get PRO Rank + FormatEx(query, sizeof(query), sql_getmaprankpro, mapID, course, mode, targetSteamID, mapID, course, mode); + txn.AddQuery(query); + // Get Number of Players with PRO Times + FormatEx(query, sizeof(query), sql_getlowestmaprankpro, mapID, course, mode); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_PrintPBs, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_PrintPBs(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int course = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + char playerName[MAX_NAME_LENGTH], mapName[33]; + + bool hasPB = false; + bool hasPBPro = false; + + float runTime; + int teleportsUsed; + int rank; + int maxRank; + + float runTimePro; + int rankPro; + int maxRankPro; + + // Get Player Name from results + if (SQL_FetchRow(results[0])) + { + SQL_FetchString(results[0], 0, playerName, sizeof(playerName)); + } + // Get Map Name from results + if (SQL_FetchRow(results[1])) + { + SQL_FetchString(results[1], 0, mapName, sizeof(mapName)); + } + if (SQL_GetRowCount(results[2]) == 0) + { + if (course == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Main Course Not Found", mapName); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Bonus Not Found", mapName, course); + } + return; + } + + // Get PB info from results + if (SQL_GetRowCount(results[3]) > 0) + { + hasPB = true; + if (SQL_FetchRow(results[3])) + { + runTime = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[3], 0)); + teleportsUsed = SQL_FetchInt(results[3], 1); + } + if (SQL_FetchRow(results[4])) + { + rank = SQL_FetchInt(results[4], 0); + } + if (SQL_FetchRow(results[5])) + { + maxRank = SQL_FetchInt(results[5], 0); + } + } + // Get PB info (Pro) from results + if (SQL_GetRowCount(results[6]) > 0) + { + hasPBPro = true; + if (SQL_FetchRow(results[6])) + { + runTimePro = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[6], 0)); + } + if (SQL_FetchRow(results[7])) + { + rankPro = SQL_FetchInt(results[7], 0); + } + if (SQL_FetchRow(results[8])) + { + maxRankPro = SQL_FetchInt(results[8], 0); + } + } + + // Print PB header to chat + if (course == 0) + { + GOKZ_PrintToChat(client, true, "%t", "PB Header", playerName, mapName, gC_ModeNamesShort[mode]); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "PB Header (Bonus)", playerName, mapName, course, gC_ModeNamesShort[mode]); + } + + // Print PB times to chat + if (!hasPB) + { + CPrintToChat(client, "%t", "PB Time - No Times"); + } + else if (!hasPBPro) + { + CPrintToChat(client, "%t", "PB Time - NUB", GOKZ_FormatTime(runTime), teleportsUsed, rank, maxRank); + CPrintToChat(client, "%t", "PB Time - No PRO Time"); + } + else if (teleportsUsed == 0) + { // Their MAP PB has 0 teleports, and is therefore also their PRO PB + CPrintToChat(client, "%t", "PB Time - NUB and PRO", GOKZ_FormatTime(runTime), rank, maxRank, rankPro, maxRankPro); + } + else + { + CPrintToChat(client, "%t", "PB Time - NUB", GOKZ_FormatTime(runTime), teleportsUsed, rank, maxRank); + CPrintToChat(client, "%t", "PB Time - PRO", GOKZ_FormatTime(runTimePro), rankPro, maxRankPro); + } +} + +void DB_PrintPBs_FindMap(int client, int targetSteamID, const char[] mapSearch, int course, int mode) +{ + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(targetSteamID); + data.WriteString(mapSearch); + data.WriteCell(course); + data.WriteCell(mode); + + DB_FindMap(mapSearch, DB_TxnSuccess_PrintPBs_FindMap, data, DBPrio_Low); +} + +public void DB_TxnSuccess_PrintPBs_FindMap(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int targetSteamID = data.ReadCell(); + char mapSearch[33]; + data.ReadString(mapSearch, sizeof(mapSearch)); + int course = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + // Check if the map course exists in the database + if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Map Not Found", mapSearch); + return; + } + else if (SQL_FetchRow(results[0])) + { // Result is the MapID + DB_PrintPBs(client, targetSteamID, SQL_FetchInt(results[0], 0), course, mode); + if (gB_GOKZGlobal) + { + char map[33], steamid[32]; + SQL_FetchString(results[0], 1, map, sizeof(map)); + GetSteam2FromAccountId(steamid, sizeof(steamid), targetSteamID); + GOKZ_GL_PrintRecords(client, map, course, GOKZ_GetCoreOption(client, Option_Mode), steamid); + } + } +} + +void DB_PrintPBs_FindPlayerAndMap(int client, const char[] playerSearch, const char[] mapSearch, int course, int mode) +{ + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteString(playerSearch); + data.WriteString(mapSearch); + data.WriteCell(course); + data.WriteCell(mode); + + DB_FindPlayerAndMap(playerSearch, mapSearch, DB_TxnSuccess_PrintPBs_FindPlayerAndMap, data, DBPrio_Low); +} + +public void DB_TxnSuccess_PrintPBs_FindPlayerAndMap(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + char playerSearch[MAX_NAME_LENGTH]; + data.ReadString(playerSearch, sizeof(playerSearch)); + char mapSearch[33]; + data.ReadString(mapSearch, sizeof(mapSearch)); + int course = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Player Not Found", playerSearch); + return; + } + else if (SQL_GetRowCount(results[1]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Map Not Found", mapSearch); + return; + } + else if (SQL_FetchRow(results[0]) && SQL_FetchRow(results[1])) + { + int accountid = SQL_FetchInt(results[0], 0); + DB_PrintPBs(client, accountid, SQL_FetchInt(results[1], 0), course, mode); + if (gB_GOKZGlobal) + { + char map[33], steamid[32]; + SQL_FetchString(results[1], 1, map, sizeof(map)); + GetSteam2FromAccountId(steamid, sizeof(steamid), accountid); + GOKZ_GL_PrintRecords(client, map, course, GOKZ_GetCoreOption(client, Option_Mode), steamid); + } + } +} diff --git a/sourcemod/scripting/gokz-localranks/db/print_records.sp b/sourcemod/scripting/gokz-localranks/db/print_records.sp new file mode 100644 index 0000000..b5de03b --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/print_records.sp @@ -0,0 +1,173 @@ +/* + Prints the record times on a map course and given mode. +*/ + + + +void DB_PrintRecords(int client, int mapID, int course, int mode) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(course); + data.WriteCell(mode); + + Transaction txn = SQL_CreateTransaction(); + + // Retrieve Map Name of MapID + FormatEx(query, sizeof(query), sql_maps_getname, mapID); + txn.AddQuery(query); + // Check for existence of map course with that MapID and Course + FormatEx(query, sizeof(query), sql_mapcourses_findid, mapID, course); + txn.AddQuery(query); + + // Get Map WR + FormatEx(query, sizeof(query), sql_getmaptop, mapID, course, mode, 1); + txn.AddQuery(query); + // Get PRO WR + FormatEx(query, sizeof(query), sql_getmaptoppro, mapID, course, mode, 1); + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_PrintRecords, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_PrintRecords(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int course = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + char mapName[33]; + + bool mapHasRecord = false; + bool mapHasRecordPro = false; + + char recordHolder[33]; + float runTime; + int teleportsUsed; + + char recordHolderPro[33]; + float runTimePro; + + // Get Map Name from results + if (SQL_FetchRow(results[0])) + { + SQL_FetchString(results[0], 0, mapName, sizeof(mapName)); + } + // Check if the map course exists in the database + if (SQL_GetRowCount(results[1]) == 0) + { + if (course == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Main Course Not Found", mapName); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Bonus Not Found", mapName, course); + } + return; + } + + // Get WR info from results + if (SQL_GetRowCount(results[2]) > 0) + { + mapHasRecord = true; + if (SQL_FetchRow(results[2])) + { + SQL_FetchString(results[2], 2, recordHolder, sizeof(recordHolder)); + runTime = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[2], 3)); + teleportsUsed = SQL_FetchInt(results[2], 4); + } + } + // Get Pro WR info from results + if (SQL_GetRowCount(results[3]) > 0) + { + mapHasRecordPro = true; + if (SQL_FetchRow(results[3])) + { + SQL_FetchString(results[3], 2, recordHolderPro, sizeof(recordHolderPro)); + runTimePro = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[3], 3)); + } + } + + // Print WR header to chat + if (course == 0) + { + GOKZ_PrintToChat(client, true, "%t", "WR Header", mapName, gC_ModeNamesShort[mode]); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "WR Header (Bonus)", mapName, course, gC_ModeNamesShort[mode]); + } + + // Print WR times to chat + if (!mapHasRecord) + { + CPrintToChat(client, "%t", "No Times Found"); + } + else if (!mapHasRecordPro) + { + CPrintToChat(client, "%t", "WR Time - NUB", GOKZ_FormatTime(runTime), teleportsUsed, recordHolder); + CPrintToChat(client, "%t", "WR Time - No PRO Time"); + } + else if (teleportsUsed == 0) + { + CPrintToChat(client, "%t", "WR Time - NUB and PRO", GOKZ_FormatTime(runTimePro), recordHolderPro); + } + else + { + CPrintToChat(client, "%t", "WR Time - NUB", GOKZ_FormatTime(runTime), teleportsUsed, recordHolder); + CPrintToChat(client, "%t", "WR Time - PRO", GOKZ_FormatTime(runTimePro), recordHolderPro); + } +} + +void DB_PrintRecords_FindMap(int client, const char[] mapSearch, int course, int mode) +{ + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteString(mapSearch); + data.WriteCell(course); + data.WriteCell(mode); + + DB_FindMap(mapSearch, DB_TxnSuccess_PrintRecords_FindMap, data, DBPrio_Low); +} + +public void DB_TxnSuccess_PrintRecords_FindMap(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + char mapSearch[33]; + data.ReadString(mapSearch, sizeof(mapSearch)); + int course = data.ReadCell(); + int mode = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + if (SQL_GetRowCount(results[0]) == 0) + { + GOKZ_PrintToChat(client, true, "%t", "Map Not Found", mapSearch); + return; + } + else if (SQL_FetchRow(results[0])) + { // Result is the MapID + DB_PrintRecords(client, SQL_FetchInt(results[0], 0), course, mode); + if (gB_GOKZGlobal) + { + char map[33]; + SQL_FetchString(results[0], 1, map, sizeof(map)); + GOKZ_GL_PrintRecords(client, map, course, GOKZ_GetCoreOption(client, Option_Mode)); + } + } +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/process_new_time.sp b/sourcemod/scripting/gokz-localranks/db/process_new_time.sp new file mode 100644 index 0000000..f9aaf73 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/process_new_time.sp @@ -0,0 +1,157 @@ +/* + Processes a newly submitted time, determining if the player beat their + personal best and if they beat the map course and mode's record time. +*/ + + + +void DB_ProcessNewTime(int client, int steamID, int mapID, int course, int mode, int style, int runTimeMS, int teleportsUsed) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(steamID); + data.WriteCell(mapID); + data.WriteCell(course); + data.WriteCell(mode); + data.WriteCell(style); + data.WriteCell(runTimeMS); + data.WriteCell(teleportsUsed); + + Transaction txn = SQL_CreateTransaction(); + + // Get Top 2 PBs + FormatEx(query, sizeof(query), sql_getpb, steamID, mapID, course, mode, 2); + txn.AddQuery(query); + // Get Rank + FormatEx(query, sizeof(query), sql_getmaprank, mapID, course, mode, steamID, mapID, course, mode); + txn.AddQuery(query); + // Get Number of Players with Times + FormatEx(query, sizeof(query), sql_getlowestmaprank, mapID, course, mode); + txn.AddQuery(query); + + if (teleportsUsed == 0) + { + // Get Top 2 PRO PBs + FormatEx(query, sizeof(query), sql_getpbpro, steamID, mapID, course, mode, 2); + txn.AddQuery(query); + // Get PRO Rank + FormatEx(query, sizeof(query), sql_getmaprankpro, mapID, course, mode, steamID, mapID, course, mode); + txn.AddQuery(query); + // Get Number of Players with PRO Times + FormatEx(query, sizeof(query), sql_getlowestmaprankpro, mapID, course, mode); + txn.AddQuery(query); + } + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_ProcessTimerEnd, DB_TxnFailure_Generic_DataPack, data, DBPrio_Normal); +} + +public void DB_TxnSuccess_ProcessTimerEnd(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int steamID = data.ReadCell(); + int mapID = data.ReadCell(); + int course = data.ReadCell(); + int mode = data.ReadCell(); + int style = data.ReadCell(); + int runTimeMS = data.ReadCell(); + int teleportsUsed = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + bool firstTime = SQL_GetRowCount(results[0]) == 1; + int pbDiff = 0; + int rank = -1; + int maxRank = -1; + if (!firstTime) + { + SQL_FetchRow(results[0]); + int pb = SQL_FetchInt(results[0], 0); + if (runTimeMS == pb) // New time is new PB + { + SQL_FetchRow(results[0]); + int oldPB = SQL_FetchInt(results[0], 0); + pbDiff = runTimeMS - oldPB; + } + else // Didn't beat PB + { + pbDiff = runTimeMS - pb; + } + } + // Get NUB Rank + SQL_FetchRow(results[1]); + rank = SQL_FetchInt(results[1], 0); + SQL_FetchRow(results[2]); + maxRank = SQL_FetchInt(results[2], 0); + + // Repeat for PRO Runs + bool firstTimePro = false; + int pbDiffPro = 0; + int rankPro = -1; + int maxRankPro = -1; + if (teleportsUsed == 0) + { + firstTimePro = SQL_GetRowCount(results[3]) == 1; + if (!firstTimePro) + { + SQL_FetchRow(results[3]); + int pb = SQL_FetchInt(results[3], 0); + if (runTimeMS == pb) // New time is new PB + { + SQL_FetchRow(results[3]); + int oldPB = SQL_FetchInt(results[3], 0); + pbDiffPro = runTimeMS - oldPB; + } + else // Didn't beat PB + { + pbDiffPro = runTimeMS - pb; + } + } + // Get PRO Rank + SQL_FetchRow(results[4]); + rankPro = SQL_FetchInt(results[4], 0); + SQL_FetchRow(results[5]); + maxRankPro = SQL_FetchInt(results[5], 0); + } + + // Call OnTimeProcessed forward + Call_OnTimeProcessed( + client, + steamID, + mapID, + course, + mode, + style, + GOKZ_DB_TimeIntToFloat(runTimeMS), + teleportsUsed, + firstTime, + GOKZ_DB_TimeIntToFloat(pbDiff), + rank, + maxRank, + firstTimePro, + GOKZ_DB_TimeIntToFloat(pbDiffPro), + rankPro, + maxRankPro); + + // Call OnNewRecord forward + bool newWR = (firstTime || pbDiff < 0) && rank == 1; + bool newWRPro = (firstTimePro || pbDiffPro < 0) && rankPro == 1; + if (newWR && newWRPro) + { + Call_OnNewRecord(client, steamID, mapID, course, mode, style, RecordType_NubAndPro, GOKZ_DB_TimeIntToFloat(pbDiffPro), teleportsUsed); + } + else if (newWR) + { + Call_OnNewRecord(client, steamID, mapID, course, mode, style, RecordType_Nub, GOKZ_DB_TimeIntToFloat(pbDiff), teleportsUsed); + } + else if (newWRPro) + { + Call_OnNewRecord(client, steamID, mapID, course, mode, style, RecordType_Pro, GOKZ_DB_TimeIntToFloat(pbDiffPro), teleportsUsed); + } +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-localranks/db/recent_records.sp b/sourcemod/scripting/gokz-localranks/db/recent_records.sp new file mode 100644 index 0000000..939b132 --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/recent_records.sp @@ -0,0 +1,171 @@ +/* + Opens the menu with a list of recently broken records for the given mode + and time type. +*/ + + + +static int recentRecordsMode[MAXPLAYERS + 1]; + + + +void DB_OpenRecentRecords(int client, int mode, int timeType) +{ + char query[1024]; + + DataPack data = new DataPack(); + data.WriteCell(GetClientUserId(client)); + data.WriteCell(mode); + data.WriteCell(timeType); + + Transaction txn = SQL_CreateTransaction(); + + switch (timeType) + { + case TimeType_Nub:FormatEx(query, sizeof(query), sql_getrecentrecords, mode, LR_PLAYER_TOP_CUTOFF); + case TimeType_Pro:FormatEx(query, sizeof(query), sql_getrecentrecords_pro, mode, LR_PLAYER_TOP_CUTOFF); + } + txn.AddQuery(query); + + SQL_ExecuteTransaction(gH_DB, txn, DB_TxnSuccess_OpenRecentRecords, DB_TxnFailure_Generic_DataPack, data, DBPrio_Low); +} + +public void DB_TxnSuccess_OpenRecentRecords(Handle db, DataPack data, int numQueries, Handle[] results, any[] queryData) +{ + data.Reset(); + int client = GetClientOfUserId(data.ReadCell()); + int mode = data.ReadCell(); + int timeType = data.ReadCell(); + delete data; + + if (!IsValidClient(client)) + { + return; + } + + // Check if there are any times + if (SQL_GetRowCount(results[0]) == 0) + { + switch (timeType) + { + case TimeType_Nub:GOKZ_PrintToChat(client, true, "%t", "No Times Found"); + case TimeType_Pro:GOKZ_PrintToChat(client, true, "%t", "No Times Found (PRO)"); + } + return; + } + + Menu menu = new Menu(MenuHandler_RecentRecordsSubmenu); + menu.Pagination = 5; + + // Set submenu title + menu.SetTitle("%T", "Recent Records Submenu - Title", client, + gC_TimeTypeNames[timeType], gC_ModeNames[mode]); + + // Add submenu items + char display[256], mapName[64], playerName[33]; + int course; + float runTime; + + while (SQL_FetchRow(results[0])) + { + SQL_FetchString(results[0], 0, mapName, sizeof(mapName)); + course = SQL_FetchInt(results[0], 1); + SQL_FetchString(results[0], 3, playerName, sizeof(playerName)); + runTime = GOKZ_DB_TimeIntToFloat(SQL_FetchInt(results[0], 4)); + + if (course == 0) + { + FormatEx(display, sizeof(display), "%s - %s (%s)", + mapName, playerName, GOKZ_FormatTime(runTime)); + } + else + { + FormatEx(display, sizeof(display), "%s B%d - %s (%s)", + mapName, course, playerName, GOKZ_FormatTime(runTime)); + } + + menu.AddItem(IntToStringEx(SQL_FetchInt(results[0], 2)), display, ITEMDRAW_DISABLED); + } + + menu.Display(client, MENU_TIME_FOREVER); +} + + + +// =====[ MENUS ]===== + +void DisplayRecentRecordsModeMenu(int client) +{ + Menu menu = new Menu(MenuHandler_RecentRecordsMode); + menu.SetTitle("%T", "Recent Records Mode Menu - Title", client); + GOKZ_MenuAddModeItems(client, menu, false); + menu.Display(client, MENU_TIME_FOREVER); +} + +void DisplayRecentRecordsTimeTypeMenu(int client, int mode) +{ + recentRecordsMode[client] = mode; + + Menu menu = new Menu(MenuHandler_RecentRecordsTimeType); + menu.SetTitle("%T", "Recent Records Menu - Title", client, gC_ModeNames[recentRecordsMode[client]]); + RecentRecordsTimeTypeAddItems(client, menu); + menu.Display(client, MENU_TIME_FOREVER); +} + +static void RecentRecordsTimeTypeAddItems(int client, Menu menu) +{ + char display[32]; + for (int timeType = 0; timeType < TIMETYPE_COUNT; timeType++) + { + FormatEx(display, sizeof(display), "%T", "Recent Records Menu - Record Type", client, gC_TimeTypeNames[timeType]); + menu.AddItem("", display, ITEMDRAW_DEFAULT); + } +} + + + +// =====[ MENU HANDLERS ]===== + +public int MenuHandler_RecentRecordsMode(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + DisplayRecentRecordsTimeTypeMenu(param1, param2); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_RecentRecordsTimeType(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + DB_OpenRecentRecords(param1, recentRecordsMode[param1], param2); + } + else if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayRecentRecordsModeMenu(param1); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_RecentRecordsSubmenu(Menu menu, MenuAction action, int param1, int param2) +{ + // TODO Menu item info is course's MapCourseID, but is currently not used + if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayRecentRecordsTimeTypeMenu(param1, recentRecordsMode[param1]); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} diff --git a/sourcemod/scripting/gokz-localranks/db/sql.sp b/sourcemod/scripting/gokz-localranks/db/sql.sp new file mode 100644 index 0000000..f768e9a --- /dev/null +++ b/sourcemod/scripting/gokz-localranks/db/sql.sp @@ -0,0 +1,411 @@ +/* + SQL query templates. +*/ + + + +// =====[ MAPS ]===== + +char sqlite_maps_alter1[] = "\ +ALTER TABLE Maps \ + ADD InRankedPool INTEGER NOT NULL DEFAULT '0'"; + +char mysql_maps_alter1[] = "\ +ALTER TABLE Maps \ + ADD InRankedPool TINYINT NOT NULL DEFAULT '0'"; + +char sqlite_maps_insertranked[] = "\ +INSERT OR IGNORE INTO Maps \ + (InRankedPool, Name) \ + VALUES (%d, '%s')"; + +char sqlite_maps_updateranked[] = "\ +UPDATE OR IGNORE Maps \ + SET InRankedPool=%d \ + WHERE Name = '%s'"; + +char mysql_maps_upsertranked[] = "\ +INSERT INTO Maps (InRankedPool, Name) \ + VALUES (%d, '%s') \ + ON DUPLICATE KEY UPDATE \ + InRankedPool=VALUES(InRankedPool)"; + +char sql_maps_reset_mappool[] = "\ +UPDATE Maps \ + SET InRankedPool=0"; + +char sql_maps_getname[] = "\ +SELECT Name \ + FROM Maps \ + WHERE MapID=%d"; + +char sql_maps_searchbyname[] = "\ +SELECT MapID, Name \ + FROM Maps \ + WHERE Name LIKE '%%%s%%' \ + ORDER BY (Name='%s') DESC, LENGTH(Name) \ + LIMIT 1"; + + + +// =====[ PLAYERS ]===== + +char sql_players_getalias[] = "\ +SELECT Alias \ + FROM Players \ + WHERE SteamID32=%d"; + +char sql_players_searchbyalias[] = "\ +SELECT SteamID32, Alias \ + FROM Players \ + WHERE Players.Cheater=0 AND LOWER(Alias) LIKE '%%%s%%' \ + ORDER BY (LOWER(Alias)='%s') DESC, LastPlayed DESC \ + LIMIT 1"; + + + +// =====[ MAPCOURSES ]===== + +char sql_mapcourses_findid[] = "\ +SELECT MapCourseID \ + FROM MapCourses \ + WHERE MapID=%d AND Course=%d"; + + + +// =====[ GENERAL ]===== + +char sql_getpb[] = "\ +SELECT Times.RunTime, Times.Teleports \ + FROM Times \ + INNER JOIN MapCourses ON MapCourses.MapCourseID=Times.MapCourseID \ + WHERE Times.SteamID32=%d AND MapCourses.MapID=%d \ + AND MapCourses.Course=%d AND Times.Mode=%d \ + ORDER BY Times.RunTime \ + LIMIT %d"; + +char sql_getpbpro[] = "\ +SELECT Times.RunTime \ + FROM Times \ + INNER JOIN MapCourses ON MapCourses.MapCourseID=Times.MapCourseID \ + WHERE Times.SteamID32=%d AND MapCourses.MapID=%d \ + AND MapCourses.Course=%d AND Times.Mode=%d AND Times.Teleports=0 \ + ORDER BY Times.RunTime \ + LIMIT %d"; + +char sql_getmaptop[] = "\ +SELECT t.TimeID, t.SteamID32, p.Alias, t.RunTime AS PBTime, t.Teleports \ + FROM Times t \ + INNER JOIN MapCourses mc ON mc.MapCourseID=t.MapCourseID \ + INNER JOIN Players p ON p.SteamID32=t.SteamID32 \ + LEFT OUTER JOIN Times t2 ON t2.SteamID32=t.SteamID32 \ + AND t2.MapCourseID=t.MapCourseID AND t2.Mode=t.Mode AND t2.RunTime= nubRecordTime) + { + gB_RecordMissed[client][TimeType_Nub] = true; + + // Check if nub record is also the pro record, and call the forward appropriately + if (proRecordExists && FloatAbs(nubRecordTime - proRecordTime) < EPSILON) + { + gB_RecordMissed[client][TimeType_Pro] = true; + Call_OnRecordMissed(client, nubRecordTime, course, mode, Style_Normal, RecordType_NubAndPro); + } + else + { + Call_OnRecordMissed(client, nubRecordTime, course, mode, Style_Normal, RecordType_Nub); + } + } + else if (proRecordExists && !proRecordMissed && currentTime >= proRecordTime) + { + gB_RecordMissed[client][TimeType_Pro] = true; + Call_OnRecordMissed(client, proRecordTime, course, mode, Style_Normal, RecordType_Pro); + } +} + + + +// =====[ MISSED PB TRACKING ]===== + +#define MISSED_PB_SOUND "buttons/button18.wav" + +void ResetPBMissed(int client) +{ + for (int timeType = 0; timeType < TIMETYPE_COUNT; timeType++) + { + gB_PBMissed[client][timeType] = false; + } +} + +void UpdatePBMissed(int client) +{ + if (!GOKZ_GetTimerRunning(client) || gB_PBMissed[client][TimeType_Nub] && gB_PBMissed[client][TimeType_Pro]) + { + return; + } + + int course = GOKZ_GetCourse(client); + int mode = GOKZ_GetCoreOption(client, Option_Mode); + float currentTime = GOKZ_GetTime(client); + + bool nubPBExists = gB_PBExistsCache[client][course][mode][TimeType_Nub]; + float nubPBTime = gF_PBTimesCache[client][course][mode][TimeType_Nub]; + bool nubPBMissed = gB_PBMissed[client][TimeType_Nub]; + bool proPBExists = gB_PBExistsCache[client][course][mode][TimeType_Pro]; + float proPBTime = gF_PBTimesCache[client][course][mode][TimeType_Pro]; + bool proPBMissed = gB_PBMissed[client][TimeType_Pro]; + + if (nubPBExists && !nubPBMissed && currentTime >= nubPBTime) + { + gB_PBMissed[client][TimeType_Nub] = true; + + // Check if nub PB is also the pro PB, and call the forward appropriately + if (proPBExists && FloatAbs(nubPBTime - proPBTime) < EPSILON) + { + gB_PBMissed[client][TimeType_Pro] = true; + Call_OnPBMissed(client, nubPBTime, course, mode, Style_Normal, RecordType_NubAndPro); + } + else + { + Call_OnPBMissed(client, nubPBTime, course, mode, Style_Normal, RecordType_Nub); + } + } + else if (proPBExists && !proPBMissed && currentTime >= proPBTime) + { + gB_PBMissed[client][TimeType_Pro] = true; + Call_OnPBMissed(client, proPBTime, course, mode, Style_Normal, RecordType_Pro); + } +} + +void DoPBMissedReport(int client, float pbTime, int recordType) +{ + switch (recordType) + { + case RecordType_Nub:GOKZ_PrintToChat(client, true, "%t", "Missed PB (NUB)", GOKZ_FormatTime(pbTime)); + case RecordType_Pro:GOKZ_PrintToChat(client, true, "%t", "Missed PB (PRO)", GOKZ_FormatTime(pbTime)); + case RecordType_NubAndPro:GOKZ_PrintToChat(client, true, "%t", "Missed PB (NUB and PRO)", GOKZ_FormatTime(pbTime)); + } + GOKZ_EmitSoundToClient(client, MISSED_PB_SOUND, _, "Missed PB"); +} \ No newline at end of file -- cgit v1.2.3