PDA

View Full Version : Mapchooser with vote statistics


Johnny got his gun
01-24-2007, 13:34
OK I'm posting this here as I've really got no intention yet of releasing this. I think it should work though. It's the same Mapchooser as in base package, just it adds a statistics collection feature thingy, I use it with Sqlite. Just to keep track of which map people vote for. The plugin logs the map votes into some table in a database. The plugin doesn't contain any way of seeing this data, you'll have to make use of the database yourself. I made a simple SQL line to sort maps like this:

CREATE VIEW [Top maps] AS
SELECT map_name as Map, SUM(result) as Score, COUNT(*) as Occurances FROM koppling, maps WHERE maps.map_id = koppling.map_id GROUP BY Map ORDER BY Score DESC;

It can end up like this, example from my test server:


RecNo Map Score Occurances
1 fy_simpsons 142 86
2 fy_iceworld_cz 134 82
3 fy_pool_day 131 79
4 gg_boot-camp 115 100
5 fy_waterland_cz 108 91
6 mindmaze2 102 95
7 cs_crackhouse 99 91
8 cs_triggerhappy 43 60
9 fy_iceworld3000 10 2
10 ka_japarena 5 4

Score is the # of votes on a certain map, and Occurances is the number of appearances in Mapchooser vote sessions.

What you wanna do with it from here I don't know but... maybe it can give people some idea? Of what maps to remove cause they're impopular, and so on...

However as I've been out for a while I might not really have kept up with the latest do:s and don't:s. Feel free to comment on the coding, especially the new SQL interface which I'm not sure I've used correctly.

/* AMX Mod X
* Nextmap Chooser Plugin
*
* by the AMX Mod X Development Team
* originally developed by OLO
*
* This file is part of AMX Mod X.
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/

#include <amxmodx>
#include <amxmisc>
#include <sqlx>

#define MAX_MAPS 128
#define SELECTMAPS 5

new g_mapName[MAX_MAPS][32]
new g_mapNums

new g_nextName[SELECTMAPS]
new g_voteCount[SELECTMAPS + 2]
new g_mapVoteNum
new g_teamScore[2]
new g_lastMap[32]

new g_coloredMenus
new bool:g_selected = false

public plugin_init()
{
register_plugin("Nextmap Chooser", AMXX_VERSION_STR, "AMXX Dev Team")
register_dictionary("mapchooser.txt")
register_dictionary("common.txt")

new MenuName[64]

format(MenuName, 63, "%L", "en", "CHOOSE_NEXTM")
register_menucmd(register_menuid(MenuName), (-1^(-1<<(SELECTMAPS+2))), "countVote")
register_cvar("amx_extendmap_max", "90")
register_cvar("amx_extendmap_step", "15")

if (cstrike_running())
register_event("TeamScore", "team_score", "a")

get_localinfo("lastMap", g_lastMap, 31)
set_localinfo("lastMap", "")

new maps_ini_file[64]
get_configsdir(maps_ini_file, 63);
format(maps_ini_file, 63, "%s/maps.ini", maps_ini_file);

if (!file_exists(maps_ini_file))
get_cvar_string("mapcyclefile", maps_ini_file, 63)
if (loadSettings(maps_ini_file))
set_task(15.0, "voteNextmap", 987456, "", 0, "b")

g_coloredMenus = colored_menus()

register_concmd("amx_votenextmap", "voteNextmap", ADMIN_CFG, "- start a vote for next map")
register_cvar("amx_mapchooserstatsfile", "mapchooser_stats.db3")
// This is a way to do a simple "Top maps" listing:
// SELECT map_name as Map, SUM(result) as Score, COUNT(*) as Occurances FROM koppling, maps WHERE maps.map_id = koppling.map_id GROUP BY Map ORDER BY Score DESC
}

public checkVotes()
{
// STATS BELOW
for (new a = 0; a < g_mapVoteNum; a++) {
server_print("%d. %s = %d", a + 1, g_mapName[g_nextName[a]], g_voteCount[a])
}

//new defaultsqltype[128]
//get_cvar_string("amx_sql_type", defaultsqltype, 127)
//set_cvar_string("amx_sql_type", "sqlite")

// Write to database. (error buffer is for errors later)
new statsfile[256], error[256]
get_datadir(statsfile, 255)
// amx_mapchooserstatsfile
get_cvar_string("amx_mapchooserstatsfile", error, 255)
format(statsfile, 255, "%s/%s", statsfile, error)

// Connect db
new Handle:tuple = SQL_MakeDbTuple("", "", "", statsfile)
//server_print("statsfile: %s", statsfile)
new errorCode
new Handle:db = SQL_Connect(tuple, errorCode, error, 255)
if (db == Empty_Handle)
log_amx("Connection failed!")
else {
//server_print("Connected to sqlite db!")

// Create tables
if (!sqlite_TableExists(db, "voteset")) {
new Handle:query = SQL_PrepareQuery(db, "\
CREATE TABLE [voteset] (\
[voteset_id] INTEGER PRIMARY KEY AUTOINCREMENT,\
[voteset_timestamp] INTEGER NOT NULL);\
")
SQL_Execute(query)
SQL_FreeHandle(query)
}
if (!sqlite_TableExists(db, "koppling")) {
new Handle:query = SQL_PrepareQuery(db, "\
CREATE TABLE [koppling] (\
[voteset_id] INTEGER,\
[map_id] INTEGER,\
[result] INTEGER NOT NULL,\
CONSTRAINT [sqlite_autoindex_koppling_1] PRIMARY KEY ([voteset_id], [map_id]));\
")
SQL_Execute(query)
SQL_FreeHandle(query)
}
if (!sqlite_TableExists(db, "maps")) {
new Handle:query = SQL_PrepareQuery(db, "\
CREATE TABLE [maps] (\
[map_id] INTEGER PRIMARY KEY AUTOINCREMENT,\
[map_name] VARCHAR(256) NOT NULL);\
CREATE UNIQUE INDEX [unik] ON [maps] ([map_name]);\
")
SQL_Execute(query)
SQL_FreeHandle(query)
}

// Create the voteset record
new timestamp = get_systime()
new Handle:query = SQL_PrepareQuery(db, "INSERT INTO voteset (voteset_timestamp) VALUES (%d)", timestamp)
if (SQL_Execute(query) == 0) {
errorCode = SQL_QueryError(query, error, 255)
log_amx("Failed creating voteset! Error code: %d, Error: %s", errorCode, error)
SQL_FreeHandle(query)
}
else {
new voteset_id = SQL_GetInsertId(query)
SQL_FreeHandle(query)
//server_print("Created voteset. Getting voteset_id = %d", voteset_id)
// Insert/get map names and their ids
new map_id
for (new i = 0; i < g_mapVoteNum; i++) {
query = SQL_PrepareQuery(db, "SELECT map_id FROM maps WHERE map_name = ^"%s^"", g_mapName[g_nextName[i]])
if (SQL_Execute(query) == 0) {
errorCode = SQL_QueryError(query, error, 255)
log_amx("Failed selecting mapname! Breaking! Error code: %d, Error: %s", errorCode, error)
SQL_FreeHandle(query)
// Should also delete voteset here? :-P
break
}
//server_print("Records returned: %d", SQL_NumResults(query))
if (!SQL_MoreResults(query)) {
SQL_FreeHandle(query)
// Do insert of mapname
query = SQL_PrepareQuery(db, "INSERT INTO maps (map_name) VALUES (^"%s^")", g_mapName[g_nextName[i]])
if (SQL_Execute(query) == 0) {
errorCode = SQL_QueryError(query, error, 255)
log_amx("Failed inserting mapname! Breaking! Error code: %d, Error: %s", errorCode, error)
SQL_FreeHandle(query)
// Should also delete voteset here? :-P
break
}
map_id = SQL_GetInsertId(query)
SQL_FreeHandle(query)
}
else {
// Get the map_id from resultset
//SQL_NextRow(query)
map_id = SQL_ReadResult(query, 0)
SQL_FreeHandle(query)
}
//server_print("map_id = %d", map_id)

// Now insert into koppling
//server_print("INSERT INTO koppling (map_id, voteset_id, result) VALUES (%d, %d, %d)", map_id, voteset_id, g_voteCount[i])
query = SQL_PrepareQuery(db, "INSERT INTO koppling (map_id, voteset_id, result) VALUES (%d, %d, %d)", map_id, voteset_id, g_voteCount[i])
if (SQL_Execute(query) == 0) {
errorCode = SQL_QueryError(query, error, 255)
log_amx("Failed inserting into koppling! Breaking! Error code: %d, Error: %s", errorCode, error)
SQL_FreeHandle(query)
// Should also delete voteset here? :-P
break
}
SQL_FreeHandle(query)
//server_print("Insert OK")
//server_print("%d = %s = %d, %d", a, g_mapName[g_nextName[a]], g_voteCount[a], g_nextName[a])
}
}
}
SQL_FreeHandle(db)
//set_cvar_string("amx_sql_type", defaultsqltype)
// STATS ABOVE

new b = 0

for (new a = 0; a < g_mapVoteNum; ++a)
if (g_voteCount[b] < g_voteCount[a])
b = a


if (g_voteCount[SELECTMAPS] > g_voteCount[b]
&& g_voteCount[SELECTMAPS] > g_voteCount[SELECTMAPS+1])
{
new mapname[32]

get_mapname(mapname, 31)
new Float:steptime = get_cvar_float("amx_extendmap_step")
set_cvar_float("mp_timelimit", get_cvar_float("mp_timelimit") + steptime)
client_print(0, print_chat, "%L", LANG_PLAYER, "CHO_FIN_EXT", steptime)
log_amx("Vote: Voting for the nextmap finished. Map %s will be extended to next %.0f minutes", mapname, steptime)

return
}

if (g_voteCount[b] && g_voteCount[SELECTMAPS + 1] <= g_voteCount[b])
{
set_cvar_string("amx_nextmap", g_mapName[g_nextName[b]])
}

new smap[32]

get_cvar_string("amx_nextmap", smap, 31)
client_print(0, print_chat, "%L", LANG_PLAYER, "CHO_FIN_NEXT", smap)
server_print("Vote: Voting for the nextmap finished. The nextmap will be %s", smap)
}

public countVote(id, key)
{
if (get_cvar_float("amx_vote_answers"))
{
new name[32]
get_user_name(id, name, 31)

if (key == SELECTMAPS)
client_print(0, print_chat, "%L", LANG_PLAYER, "CHOSE_EXT", name)
else if (key < SELECTMAPS)
client_print(0, print_chat, "%L", LANG_PLAYER, "X_CHOSE_X", name, g_mapName[g_nextName[key]])
}
++g_voteCount[key]

return PLUGIN_HANDLED
}

bool:isInMenu(id)
{
for (new a = 0; a < g_mapVoteNum; ++a)
if (id == g_nextName[a])
return true
return false
}

public voteNextmap()
{
new winlimit = get_cvar_num("mp_winlimit")
new maxrounds = get_cvar_num("mp_maxrounds")

if (winlimit)
{
new c = winlimit - 2

if ((c > g_teamScore[0]) && (c > g_teamScore[1]))
{
g_selected = false
return
}
}
else if (maxrounds)
{
if ((maxrounds - 2) > (g_teamScore[0] + g_teamScore[1]))
{
g_selected = false
return
}
} else {
new timeleft = get_timeleft()

if (timeleft < 1 || timeleft > 129)
{
g_selected = false
return
}
}

if (g_selected)
return

g_selected = true

new menu[512], a, mkeys = (1<<SELECTMAPS + 1)
new pos = format(menu, 511, g_coloredMenus ? "\y%L:\w^n^n" : "%L:^n^n", LANG_SERVER, "CHOOSE_NEXTM")
new dmax = (g_mapNums > SELECTMAPS) ? SELECTMAPS : g_mapNums

for (g_mapVoteNum = 0; g_mapVoteNum < dmax; ++g_mapVoteNum)
{
a = random_num(0, g_mapNums - 1)

while (isInMenu(a))
if (++a >= g_mapNums) a = 0

g_nextName[g_mapVoteNum] = a
pos += format(menu[pos], 511, "%d. %s^n", g_mapVoteNum + 1, g_mapName[a])
mkeys |= (1<<g_mapVoteNum)
g_voteCount[g_mapVoteNum] = 0
}

menu[pos++] = '^n'
g_voteCount[SELECTMAPS] = 0
g_voteCount[SELECTMAPS + 1] = 0

new mapname[32]
get_mapname(mapname, 31)

if ((winlimit + maxrounds) == 0 && (get_cvar_float("mp_timelimit") < get_cvar_float("amx_extendmap_max")))
{
pos += format(menu[pos], 511, "%d. %L^n", SELECTMAPS + 1, LANG_SERVER, "EXTED_MAP", mapname)
mkeys |= (1<<SELECTMAPS)
}

format(menu[pos], 511, "%d. %L", SELECTMAPS+2, LANG_SERVER, "NONE")
new MenuName[64]

format(MenuName, 63, "%L", "en", "CHOOSE_NEXTM")
show_menu(0, mkeys, menu, 15, MenuName)
set_task(15.0, "checkVotes")
client_print(0, print_chat, "%L", LANG_SERVER, "TIME_CHOOSE")
client_cmd(0, "spk Gman/Gman_Choose2")
log_amx("Vote: Voting for the nextmap started")

server_print(menu)
}

loadSettings(filename[])
{
if (!file_exists(filename))
return 0

new szText[32]
new a, pos = 0
new currentMap[32]

get_mapname(currentMap, 31)

while ((g_mapNums < MAX_MAPS) && read_file(filename, pos++, szText, 31, a))
{
if (szText[0] != ';' && parse(szText, g_mapName[g_mapNums], 31) && is_map_valid(g_mapName[g_mapNums])
&& !equali(g_mapName[g_mapNums], g_lastMap) && !equali(g_mapName[g_mapNums], currentMap))
++g_mapNums
}

return g_mapNums
}

public team_score()
{
new team[2]

read_data(1, team, 1)
g_teamScore[(team[0]=='C') ? 0 : 1] = read_data(2)
}

public plugin_end()
{
new current_map[32]

get_mapname(current_map, 31)
set_localinfo("lastMap", current_map)
}

rosetattoo
04-04-2007, 05:39
..yeah !

Podunk
05-05-2007, 21:44
this mod rules, no ... YOU RULE JGHG!

I use a highly modded version of your rememberthefrags too.

thanks!