/* RANDOM-MAP-VOTE (LogD)
(c)by Sir Drink a lot 13.05.03
 
Beschreibung:
--------------------------
- ließt alle Maps aus einer mapvote.ini aus und stellt max. 8 Maps kurz
vor Mapende als grafischen Vote zur Auswahl.
 
Notwendige Einstellungen:
-------------------------- 
ab v0.83: 
- automatischer Start der Nominierungsphase
- LogD muss installiert sein.
- "log on" muss aktiviert sein, um logs zu empfangen.
 
ab v0.81:
- Sounds können in der vault.ini hinterlegt werden.
 RMV_VOTENOW pfad/datei.wav -> Dieser Sounds wird zu Beginn der Nominierungsphase sowie zum Votestart abgespielt.
 RMV_VOTEPASSED pfad/datei.wav -> Dieser Sound wird abgespielt, wenn der Vote erfolgreich war.
 RMV_VOTEFAILED pfad/datei.wav -> Dieser Sound wird abgespielt, wenn der Vote nicht erfolgreich war.
 
 Damit die Clients selber entscheiden können, ob sie diese Sounds hören wollen, wird das Plugin sdal_allowsounds
 benötigt. Damit kann der Client dann durch die Chateingaben /stop bzw. /play das Abspielen der Sounds bei sich
 abstellen bzw. auch wieder aktivieren. Ohne das Plugin, werden allen Clients die Sounds abgespielt, ausser
 sie haben bei sich manuell in der config.cfg setinfo "am_sound" "0" eingetragen.
- allow_client_exec muss auf 1 stehen, damit die Sounds abgespielt werden können.
 
ab v.08:
- in der adminmod.cfg muss amv_enable_beta menu1 aktiviert sein.
- die vault.ini muss vorhanden und in der adminmod.cfg definiert sein.
 
Changelog:
--------------------------
v.0.85: - gefraggten Spielern, die noch nicht gevotet haben, wird das VoteMenü angezeigt.
v.083:  - eigenes Zeitmanagement unter Verwendung von LogD
v.082:	- how many maps are restricted can be set by MAX_MAP_RESTRICT now.
	- changed menu option 0 from "0. keine davon" to "0. nextmap: xyz"
v.081: 	- added Sounds
	- removed useless timerfunctions
	- admin_vote_stop should work correctly now.
	- nominate time, warn time and vote time can be changed easily in source
v.08: 	- Initial Release
*/
 
#include <core>
#include <console>
#include <string>
#include <admin>
#include <adminlib>
 
#define ACCESS_CONSOLE 131072
 
new AM_VERSION_STRING[] = "2.50.58_v085";
 
/************************************************************/
/* KANN ENTSPRECHEND EDITIERT UND DANN NEU KOMPILIERT WERDEN*/
/************************************************************/
/*Mapfile*/
new g_Mapfile[MAX_TEXT_LENGTH]="addons/adminmod/config/mapvote.ini";	
/*Maps*/
#define MAX_MAPS	30	/*max. Anzahl der Maps in der mapvote.ini*/
/*Vote-Time*/
new g_setvotetime 	= 120;	/*2 Min vor Mapende*/
new g_setvotewarntime 	= 20;	/*alle 20 sek. ein Vote-Hinweis*/
/************************************************************/
 
/*Vote*/
new g_NominatedMaps[9][MAX_NAME_LENGTH];
new g_vote_start;
new g_vote_canceled;
 
/*Sounds*/
new g_VoteNow[MAX_TEXT_LENGTH];
new g_VoteFailed[MAX_TEXT_LENGTH];
new g_VotePassed[MAX_TEXT_LENGTH];
 
/*Menu*/
new g_UserVoteMenu[MAX_PLAYERS];
new g_UserSelect[MAX_PLAYERS];
 
/*Map-Settings*/
new g_CurrentMap[MAX_NAME_LENGTH];
new g_NextMap[MAX_NAME_LENGTH];
new g_curextend;
/*loaded Maps and how often they are voted*/
new g_Maps[MAX_MAPS][MAX_NAME_LENGTH];
new g_PlayedBefore[MAX_MAPS];
new g_loaded;
 
/*Time-Settings*/
new g_origtimelimit;
new g_newtimelimit;
new g_timelimit;
new g_checktime;
new g_TimerIndex;
new g_countdown;
new g_TimerWarnIndex;
 
public plugin_init() {
	if(fileexists(g_Mapfile)){
		plugin_registerinfo("RANDOM-MAP-VOTE","Grafischer Vote mit zufalliger Mapauswahl",AM_VERSION_STRING);
		plugin_registercmd("admin_vote_random","start_vote",ACCESS_VOTE_MAP,"admin_vote_random: starts vote of 8 maps");
		plugin_registercmd("admin_vote_stop","stop_vote",ACCESS_VOTE_MAP,"admin_vote_stop: stops map-nomination and vote");
		plugin_registercmd("admin_vote_sort","sortlist",ACCESS_RCON,"admin_vote_sort: sorts the mapvote.ini to most played maps");
		plugin_registercmd("say","HandleSay",ACCESS_ALL,"vote mapname: make suggestions for mapchange");
		plugin_registercmd("menuselect","menuselect",ACCESS_ALL);
		plugin_registercmd("radio1","SetMenuData",ACCESS_ALL);
		plugin_registercmd("radio2","SetMenuData",ACCESS_ALL);
		plugin_registercmd("radio3","SetMenuData",ACCESS_ALL);
		plugin_registercmd("buyequip","SetMenuData",ACCESS_ALL);
		plugin_registercmd("buy","SetMenuData",ACCESS_ALL);
		plugin_registercmd("chooseteam","SetMenuData",ACCESS_ALL);
		plugin_registercmd("showbriefing","SetMenuData",ACCESS_ALL);
		plugin_registercmd("rmv_world","rmv_world",ACCESS_CONSOLE);
		plugin_registercmd("rmv_kill","rmv_kill",ACCESS_CONSOLE);
		exec( "logd_reg 57 admin_command rmv_kill" );
		exec( "logd_reg 62 admin_command rmv_world" );
 
		/*Map-Settings*/
		currentmap(g_CurrentMap,MAX_NAME_LENGTH);
		nextmap(g_NextMap,MAX_NAME_LENGTH);
 
		new Data[MAX_DATA_LENGTH];
		new sNumber[3];
		new iFileSize = filesize(g_Mapfile);
		new i;
		/*Maps laden*/
		if(iFileSize > MAX_MAPS){
			iFileSize=MAX_MAPS;
			selfmessage("[RANDOM-MAP-VOTE] MAX_MAPS muss im Source-Code des Plugins erhoeht werden, damit alle Maps aus der mapvote.ini geladen werden koennen!");
		}
		for(i=1;i<=iFileSize;i++){
			readfile(g_Mapfile,Data,i,MAX_DATA_LENGTH);
			strsplit(Data,":",g_Maps[g_loaded],MAX_NAME_LENGTH,sNumber,3);
			g_PlayedBefore[g_loaded]=strtonum(sNumber);
			if(strcmp(g_CurrentMap,g_Maps[g_loaded])==0){
				g_PlayedBefore[g_loaded]+=1;
				snprintf(Data,MAX_DATA_LENGTH,"%s:%i",g_Maps[g_loaded],g_PlayedBefore[g_loaded]);
				writefile(g_Mapfile,Data,i);
			}
			g_loaded++;
		}
		g_loaded--;
 
		/*Time-Settings*/
		g_origtimelimit=	getvar("mp_timelimit");
		g_newtimelimit =	g_origtimelimit;
		g_checktime=		systemtime();
 
		/*Sound-Settings*/
		get_vaultdata( "RMV_VOTENOW", g_VoteNow, MAX_TEXT_LENGTH );
		get_vaultdata( "RMV_VOTEPASSED", g_VotePassed, MAX_TEXT_LENGTH );
		get_vaultdata( "RMV_VOTEFAILED", g_VoteFailed, MAX_TEXT_LENGTH );
	}else{
		plugin_registerinfo("RANDOM-MAP-VOTE","Konnte mapvote.ini nicht finden!",AM_VERSION_STRING);
		selfmessage("[RANDOM-MAP-VOTE] Konnte mapvote.ini nicht finden!");
	}		
	return PLUGIN_CONTINUE;
}
 
/////////////////////////////
// VOTE - SOUNDS unter     //
// Berücksichtigung des	   //
// PLUGIN_SDAL_ALLOWSOUNDS //
/////////////////////////////
 
sound_all(Sound[]){
	if(strlen(Sound)!=0){
		new Name[MAX_NAME_LENGTH];
		new maxplayers = maxplayercount();
		new i;
		for(i=1;i<=maxplayers; i++ ){
			if( playerinfo(i, Name, MAX_NAME_LENGTH)){
				if(allowsound(Name)==1){
					playsound(Name,Sound);
				}
			}
		}
	}
}
 
allowsound(User[]){
	new Key[]="am_sound";
	new Info[MAX_NUMBER_LENGTH];
	new iInfo;
	new Authid[MAX_AUTHID_LENGTH];
	get_userAuthID(User,Authid,MAX_AUTHID_LENGTH);
	if(strcmp(Authid,"BOT")!=0){
		get_userinfo(User,Key,Info,MAX_NUMBER_LENGTH);
		iInfo=strtonum(Info);
		if(strlen(Info)==0 || iInfo > 0){/*damit wird automatisch immer der Sound auf 1 gesetzt,wenn kein setinfo vorhanden, bis 'stop' eingegeben wird*/
			return 1;
		}
	}
	return 0;
}
 
////////////////////////////
// LOGD-MAPZEIT-KONTROLLE //
////////////////////////////
public rmv_world(HLCommand,HLData,HLUserName,UserIndex){
	new Data[MAX_NAME_LENGTH];
   	convert_string(HLData,Data,MAX_NAME_LENGTH); 
    	if(Data[0]=='G' || Data[8]=='R'){
    		g_checktime=systemtime();
    		g_timelimit=0;
    	}
    	time_change();
        return PLUGIN_CONTINUE;
}
 
time_change(){
	new settimer;
	if (getvar("mp_timelimit")*60!= g_timelimit){
		g_timelimit=getvar("mp_timelimit")*60;
		if(g_TimerWarnIndex!=0){
			kill_timer(g_TimerWarnIndex);
			g_TimerWarnIndex=0;
		}
		if(g_TimerIndex!=0){
			kill_timer(g_TimerIndex);
			g_TimerIndex=0;
		}
		g_vote_start=0;
		g_vote_canceled=1;
		settimer= g_timelimit-(systemtime()-g_checktime)-g_setvotetime;
		g_TimerIndex=set_timer("exec_vote",settimer,0);
        }
}
 
public exec_vote(Timer,Repeat,HLName,HLParam) {
	g_TimerIndex=0;
	starting_vote();
	return PLUGIN_CONTINUE;
}
 
//////////////////////////
// LOGD-KILL, um toten  //
// Spielern, die noch   //
// nicht gevotet haben, //
// das Menü anzuzeigen. //
//////////////////////////
public rmv_kill(HLCommand,HLData,HLUserName,UserIndex){
	if(g_vote_start){
		new Data[MAX_NAME_LENGTH];
		new Player[MAX_NAME_LENGTH];
		new Weapon[MAX_NAME_LENGTH];
		new sAtt[3];
		new sVic[3];
		new iVic;
	   	convert_string(HLData,Data,MAX_NAME_LENGTH);
	   	strsplit(Data," ",sAtt,3,sVic,3,Weapon,MAX_NAME_LENGTH);
	   	iVic=strtonum(sVic);
	   	if(g_UserSelect[iVic]==0){
	   		if(playerinfo(iVic,Player,MAX_NAME_LENGTH)){
	   			show_vote(Player,iVic);
	   		}
	   	}
	}    	
        return PLUGIN_CONTINUE;
}
 
////////////////////
// ADMIN_COMMANDS //
////////////////////
public start_vote(HLCommand,HLData,HLUserName,UserIndex){
	starting_vote();
	return PLUGIN_HANDLED;
}
 
public stop_vote(HLCommand,HLData,HLUserName,UserIndex){
	if(g_vote_start){
		g_vote_canceled=1;
		selfmessage("[RANDOM-MAP-VOTE]: Vote wird abgebrochen!");
	}else{
		selfmessage("[RANDOM-MAP-VOTE]: Zur Zeit kein Mapvote im Gange!");
	}
	return PLUGIN_HANDLED;
}
 
public sortlist(HLCommand,HLData,HLUserName,UserIndex){
	new Data[MAX_DATA_LENGTH];
	new i;
	resetfile(g_Mapfile);
	quicksort(0,g_loaded);
	for(i=0;i<=g_loaded;i++){
		snprintf(Data,MAX_DATA_LENGTH,"%s:%i",g_Maps[i],g_PlayedBefore[i]);
		writefile(g_Mapfile,Data,-1);
	}
	selfmessage("[RANDOM-MAP-VOTE] mapvote.ini wurde sortiert!");
        return PLUGIN_HANDLED;
}
 
starting_vote(){
	new Text[MAX_TEXT_LENGTH];
	if(!g_vote_start){
		g_vote_start=1;
		g_vote_canceled=0;
		sound_all(g_VoteNow);
		calculate_maps();
		g_countdown=g_setvotetime;
		snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]:^nGebt Euren Mapvote ab!^nMapvote-Menue mit ^"votemap^"^nim Chat aufrufen!");
		centersay(Text,12,255,255,255);
		snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: Bitte Map-Vote abgeben (im Chat ^"votemap^" eingeben!). Ihr habt noch %i Sekunden Zeit!",g_countdown);
		say(Text);
		g_TimerWarnIndex=set_timer("nominate_warning",g_setvotewarntime,0);
	}else{
		snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: Ein Map-Vote ist bereits im Gange!");
		selfmessage(Text);
	}
}
 
calculate_maps(){
	new i;
	quicksort(0,g_loaded);
	/*eher unnötige, da g_Maps schon sortiert...*/
	for(i=0;i<=8;i++){
		strcpy(g_NominatedMaps[i],g_Maps[i],MAX_NAME_LENGTH);
	}
}
 
stock quicksort (lo,hi){
	new Name[MAX_NAME_LENGTH];
	new t;
	new i=lo;
	new j=hi;
	new x=g_PlayedBefore[(lo+hi)/2];
 
	//  Aufteilung
	while (i<=j)
	{    
	    while (g_PlayedBefore[i]<x){
	    	i++; 
	    }
	    while (g_PlayedBefore[j]>x){
	    	j--;
	    }
	    if (i<=j){
	    	/*Zwischenspeichern*/
	   	t=g_PlayedBefore[i];
	    	strcpy(Name,g_Maps[i],MAX_NAME_LENGTH);
	        /*Tauschen*/
        	g_PlayedBefore[i]=g_PlayedBefore[j];
        	strcpy(g_Maps[i],g_Maps[j],MAX_NAME_LENGTH);
        	g_PlayedBefore[j]=t;
        	strcpy(g_Maps[j],Name,MAX_NAME_LENGTH);
	        i++; 
	        j--;
	    }
	}
 
	// Rekursion
	if (lo<j){
		quicksort(lo, j);
	}
	if (i<hi){
		quicksort(i, hi);
	}
}
 
public nominate_warning(Timer,Repeat,HLName,HLParam) {
	g_TimerWarnIndex=0;
	new Text[MAX_TEXT_LENGTH];
	time_change();
	if(!g_vote_canceled){
		g_countdown-=g_setvotewarntime;
		if(g_countdown>0){
			snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: Bitte Map-Vote abgeben (im Chat ^"votemap^" eingeben!). Ihr habt noch %i Sekunden Zeit!",g_countdown);
			say(Text);
			g_TimerWarnIndex=set_timer("nominate_warning",g_setvotewarntime,0);
		}else{
			calculate_results();
		}
	}else{
		g_vote_start=0;
		sound_all(g_VoteFailed);
		say("[RANDOM-MAP-VOTE]: Vote wurde abgebrochen!");
		snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: Naechste Map ist %s",g_NextMap);
		say(Text);
	}
}
 
public HandleSay(HLCommand,HLData,HLUserName,UserIndex) {
	new Data[MAX_DATA_LENGTH];
	new UserName[MAX_NAME_LENGTH];
 
	convert_string(HLData,Data,MAX_DATA_LENGTH);
	convert_string(HLUserName,UserName,MAX_NAME_LENGTH);
 
	strstripquotes(Data);
 
	if(strcmp(Data,"votemap")==0){
		if(g_vote_start){
			if(g_UserSelect[UserIndex]==0){
				show_vote(UserName,UserIndex);
			}else{
				show_votechange(UserName,UserIndex);
			}
		}else{
			messageex(UserName,"[RANDOM-MAP-VOTE]: Vote hat noch nicht stattgefunden oder ist bereits abgeschlossen!",print_chat);
			return PLUGIN_HANDLED;
		}
	}
	return PLUGIN_CONTINUE;
}
 
show_vote(User[],UserIndex) {
	new VoteDisplay[512];
	new UserName[MAX_NAME_LENGTH];
	new MapName[MAX_NAME_LENGTH];
	new Text[512];
	new i;
	new x;
	new keys=1;
	new maxplayers=maxplayercount();
 
	for(i=0;i<=8;i++){
		x++;
		if(x!=1){
			keys+=keys;
		}
		if(strcasecmp(g_CurrentMap,g_NominatedMaps[i])==0){
			strcpy(MapName,"EXTEND",MAX_NAME_LENGTH);
		}else{
			strcpy(MapName,g_NominatedMaps[i],MAX_NAME_LENGTH);
		}
		snprintf(Text,512,"%s^n%i.%s",Text,x,MapName);
		if(x==8){
			keys+=keys-1;
			break;
		}
	}
	snprintf(VoteDisplay,512,"\yVOTE-MENU:^n\w%s^n^n\y0. nextmap: %s",Text,g_NextMap);
	keys=keys+512;
	if(UserIndex!=0){
		g_UserVoteMenu[UserIndex]=1;
		menu(User,VoteDisplay,keys);
	}else{
		for(i=1;i<=maxplayers;i++){
			if(playerinfo(i,UserName,MAX_NAME_LENGTH)){
				g_UserVoteMenu[i]=1;
				menu(UserName,VoteDisplay,keys);
			}
		}
	}
}
 
show_votechange(User[],UserIndex) {
	new Text[512];
	new UserVote[MAX_NAME_LENGTH];
	if(g_UserSelect[UserIndex]==10){
		snprintf(UserVote,MAX_NAME_LENGTH,"nextmap: %s",g_NextMap);
	}else{
		snprintf(UserVote,MAX_NAME_LENGTH,"%s",g_NominatedMaps[g_UserSelect[UserIndex]-1]);
	}
	snprintf(Text,MAX_TEXT_LENGTH,"\y[RANDOM-MAP-VOTE]:^n^n\wDu hast zur Zeit fuer^n\y%s^n\wabgestimmt. Willst Du den:^n^n1. Vote aendern^n0. Nein. Ist OK",UserVote);
	g_UserVoteMenu[UserIndex]=2;
	menu(User,Text,513);
}
 
public menuselect(HLCommand,HLData,HLUserName,UserIndex){
	new Data[MAX_DATA_LENGTH];
	new Text[MAX_TEXT_LENGTH];
	new User[MAX_NAME_LENGTH];
	new iSelect;
  	convert_string(HLData,Data,MAX_DATA_LENGTH);
	convert_string(HLUserName,User,MAX_NAME_LENGTH);
	if(g_UserVoteMenu[UserIndex]!=0){
		iSelect=strtonum(Data);
		if(g_UserVoteMenu[UserIndex]==1){
			if (iSelect==10){
				snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: %s hat fuer die naechste Map %s abgestimmt!",User,g_NextMap);
			}else{
				snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: %s hat fuer %s abgestimmt!",User,g_NominatedMaps[iSelect-1]);			
			}
			g_UserSelect[UserIndex]=iSelect;
			say(Text);
			reset_array(UserIndex);
			return PLUGIN_HANDLED;
		}else if(g_UserVoteMenu[UserIndex]==2){
			if(iSelect==1){
				snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: %s aendert vielleicht sein Meinung!",User);
				say(Text);
				show_vote(User,UserIndex);
				return PLUGIN_HANDLED;
			}
			return PLUGIN_HANDLED;
		}
	}
	return PLUGIN_CONTINUE;
}	
 
public SetMenuData(HLCommand,HLData,HLUserName,UserIndex){
	new UserName[MAX_NAME_LENGTH];
	new Text[MAX_TEXT_LENGTH];
	convert_string(HLUserName,UserName,MAX_NAME_LENGTH);
	if(g_UserVoteMenu[UserIndex]!=0){
		reset_array(UserIndex);
		snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: Menue wurde durch ein anderes Menue beendet! Benutze ^"votemap^" im Chat, um es nochmal aufzurufen!");
		messageex(UserName,Text,print_chat);
	}
	return PLUGIN_CONTINUE;
}
 
reset_array(UserIndex){
	g_UserVoteMenu[UserIndex]=0;
}
 
calculate_results(){
	new Text[MAX_TEXT_LENGTH];
	new UserName[MAX_NAME_LENGTH];
	new MapVotes[10];
	new maxplayers=maxplayercount();
	new i;
	new winmap;
	new winvotes;
	new votes;
	new votecount;
 
	snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]:^nVote abgeschlossen!");
	centersay(Text,12,255,255,255);
	sound_all(g_VotePassed);
 
	/*Calculating votes*/
	for(i=1;i<=maxplayers;i++){
		if(playerinfo(i,UserName,MAX_NAME_LENGTH)){
			if(g_UserSelect[i]!=0){
				MapVotes[g_UserSelect[i]-1]+=1;
				votecount++;
			}
		}
	}
	/*Find maxvotes and winning map*/
	for(i=0;i<9;i++){
		votes=max(MapVotes[i],winvotes);
		if(votes>winvotes){
			winvotes=MapVotes[i];
			winmap=i;
		}
	}
 
	if(winvotes!=0 && MapVotes[9]<winvotes){
		snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: ^"%s^" hat mit %i von %i Stimmen gewonnen!",g_NominatedMaps[winmap],winvotes,votecount);
		say(Text);
		if(strcmp(g_NominatedMaps[winmap],g_CurrentMap)==0){
			g_curextend++;
			g_newtimelimit+=g_origtimelimit;
			snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: ^"%s^" wird um %i Minuten verlaengert!",g_NominatedMaps[winmap],g_origtimelimit);
			say(Text);
			snprintf(Text,MAX_TEXT_LENGTH, "mp_timelimit %i", g_newtimelimit);
		  	exec(Text);
		}else{
			snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: Mapwechsel zu ^"%s^"!",g_NominatedMaps[winmap]);
			say(Text);
			changelevel(g_NominatedMaps[winmap],3);
		}
	}else{
		snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: Die Mehrheit will weiter nach Mapcycle spielen!");
		say(Text);
		snprintf(Text,MAX_TEXT_LENGTH,"[RANDOM-MAP-VOTE]: Naechste Map ist %s",g_NextMap);
		say(Text);
	}
}