Raised This Month: $32 Target: $400
 8% 

Mapchooser with vote statistics


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Johnny got his gun
Veteran Member
Join Date: Jan 2004
Location: Tokyo
Old 01-24-2007 , 13:34   Mapchooser with vote statistics
Reply With Quote #1

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:

Code:
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.

Code:
/* 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)
}
Johnny got his gun is offline
rosetattoo
Junior Member
Join Date: Mar 2007
Old 04-04-2007 , 05:39   Re: Mapchooser with vote statistics
Reply With Quote #2

..yeah !
rosetattoo is offline
Podunk
Senior Member
Join Date: Nov 2005
Location: Florida
Old 05-05-2007 , 21:44   Re: Mapchooser with vote statistics
Reply With Quote #3

this mod rules, no ... YOU RULE JGHG!

I use a highly modded version of your rememberthefrags too.

thanks!
Podunk is offline
Send a message via MSN to Podunk
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 19:35.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode