#include <amxmodx>
#include <amxmisc>
/*
Reads the words out of the file hangman.ini in cfg dir.
If no you don't create a file the plugin will create one with 6 words...

[Cvars]
hangman_chances		deafult: 13		description: How many chances before failure.
hangman_onlydead	deafult: 1		description: Only dead players can see the hangman and guess.
hangman_timer		deafult: 120		description: How much time to guess before failure.
hangman_autohang	deafult: 0 ( min 5 )	description: Start hangman x secons after the one before is finished. If lower than 5 ( seconds ), nothing happends.

[Commands]
say /hangman [word]	description: Start a hangman. if no word, one from the word buffer will be randomly selected.
say /guess X		description: Guess at char X.
say guess X		description: Same as above.
say X			description: Same as above.
say [word]		description: Guess at whole word.
*/

#define	ADMIN_LEVEL_PLUGIN	ADMIN_VOTE
#define	MAX_WORDS		128
#define MAX_LEN_OF_WORDS	32

#define BANNED_WORDS		5

#define SUCCESS			true
#define FAIL			false

new pCvar_only_for_dead
new pCvar_chances
new pCvar_hangtimer
new pCvar_autohang

new g_word[MAX_LEN_OF_WORDS]
new g_unsolved_word[MAX_LEN_OF_WORDS * 2]

new g_guessed[MAX_LEN_OF_WORDS][1]
new g_guessed_string[MAX_LEN_OF_WORDS * 3]

new g_word_buffer[MAX_WORDS][MAX_LEN_OF_WORDS]

new g_chances_left
new g_hang
new g_unknown
new g_words

new g_file[128]
new g_filename[32] = "/hangman.ini"

new Float:g_timer

new Disabled[BANNED_WORDS][64]
new g_curbanned

public plugin_init() {
	register_plugin("Hangman", "1.1", "[ --<@ ]")
	
	register_clcmd("say", "HandleSay")
	
	pCvar_chances = register_cvar("hangman_chances", "13")
	pCvar_only_for_dead = register_cvar("hangman_onlydead", "1")
	pCvar_hangtimer = register_cvar("hangman_timer", "120")
	pCvar_autohang = register_cvar("hangman_autohang", "0")
	
	get_configsdir(g_file, 127)
	add(g_file, 127, g_filename)
	
	buffer_words()
	
	if ( get_pcvar_num(pCvar_autohang) >= 5 )
		set_task(10.0, "start_hang")
	
}

stock buffer_words() {
	
	if ( ! file_exists(g_file) )
		write_file(g_file, "// Since lack of file, this was generated...^ngaben^nturtle^nninja^npirate^npineapple^nyam")
	
	new text[MAX_LEN_OF_WORDS]
	
	new fileh = fopen(g_file, "rt")
	
	while ( ! feof(fileh) ) {
		
		if ( g_words == MAX_WORDS )
			break
		
		fgets(fileh, text, MAX_LEN_OF_WORDS - 1)
		
		if ( ! strlen(text) || equal(text, ";", 1) || equal(text, "//", 2) || contain(text, " ") != -1 )
		continue
		
		strtoupper(text)
		
		copy(g_word_buffer[g_words], MAX_LEN_OF_WORDS - 1, text)
		
		g_words++
	}
	
	if ( fileh )
		fclose(fileh)
	
	if ( ! g_words ) {
		write_file(g_file, "// Since lack of words, this was generated...^ngaben^nturtle^nninja^npirate^npineapple^nyam")
		buffer_words()
		return
	}
	
	if ( g_words < BANNED_WORDS )
		set_fail_state("Number of 'banned' words is over number of total words.")
}

public timeout_hang() {
	
	set_task(1.0, "show_fail", 857385)
}

public update()
	update_hud()

public show_success()
	show_(SUCCESS)

public show_fail()
	show_(FAIL)

stock show_(bool:succorfail) {
	new player[32], playerNum
	
	if ( get_pcvar_num(pCvar_only_for_dead) )
		get_players(player, playerNum, "cb")
	else
		get_players(player, playerNum, "c")
	
	set_hudmessage(100, 50, 200, 0.02, 0.15, 1, 6.0, 12.0, 0.1, 0.2, 3)
	
	for ( new i = 0 ; i < playerNum ; i++ ) {
		if ( succorfail )
			show_hudmessage(player[i], "[Hangman]^n^nYou succeded, the correct word was:^n%s.", g_word)
		else
			show_hudmessage(player[i], "[Hangman]^n^nYou failed, the correct word was:^n%s^nBetter luck next time.", g_word)
	}
	
	remove_task(999332)
	
	new timer = get_pcvar_num(pCvar_autohang)
	
	if ( timer >= 5 )
		set_task(timer * 1.0, "start_hang")
}

public HandleSay(id) {
	
	if ( ! is_user_connected(id) )
		return PLUGIN_HANDLED
	
	new message[64]
	read_args(message , 64)
	trim(message)
	remove_quotes(message)
	
	new said[2][32]
	
	strbreak(message, said[0], 31, said[1], 31)
	
	if ( equali(said[0], g_word) ) {
		
		new name[32]
		get_user_name(id, name, 31)
		
		new player[32], playerNum
		
		if ( get_pcvar_num(pCvar_only_for_dead) )
			get_players(player, playerNum, "cb")
		else
			get_players(player, playerNum, "c")
		
		strtoupper(said[1])
		
		for ( new i = 0 ; i < playerNum ; i++ )
			client_print(player[i], print_chat, "[Hangman] %s guessed at %s and solved the word.", name, said[0])
		
		remove_task(999332)
		
		update_hud(true)
		
		g_hang = 0
		
		set_task(1.0, "show_success", 857385)
	}
	
	if ( equali(said[0], "/hangman") ) {
		
		if ( ! access(id, ADMIN_LEVEL_PLUGIN) )
			return PLUGIN_CONTINUE
		
		if ( start_hang(said[1]) )
			client_print(id, print_chat, "[Hangman] Hangman was started")
		else
			client_print(id, print_chat, "[Hangman] Hangman is allready started")
		
		return PLUGIN_HANDLED;
	}
	
	else if ( equali(said[0], "/guess") || equali(said[0], "guess") || strlen(said[0]) == 1 ) {
		
		if ( ! g_hang || ! g_chances_left || ( get_pcvar_num(pCvar_only_for_dead) && is_user_alive(id) ) )
			return PLUGIN_CONTINUE
		
		if ( strlen(said[0]) == 1 )
			copy(said[1], 1, said[0])
		
		remove_quotes(said[1])
		trim(said[1])
		
		
		if ( ! strlen(said[1]) ) {
			client_print(id, print_chat, "[Hangman] You must guess at one letter")
			return PLUGIN_HANDLED
		}
		
		if ( strlen(said[1]) > 1 ) {
			client_print(id, print_chat, "[Hangman] You can only guess at one letter")
			return PLUGIN_HANDLED
		}
		
		if ( is_in_guessed(said[1][0]) ) {
			client_print(id, print_chat, "[Hangman] Someone have allready guessed for %s", toupper(said[1][0]))
			return PLUGIN_HANDLED
		}
		else {
			new last = last_in_g_guessed()
			g_guessed[last][0] = toupper(said[1][0])
		}
		
		new name[32]
		get_user_name(id, name, 31)
		
		format_guessed_str()
		
		format_unsolved_word()
		
		if ( is_in_word(said[1][0]) ) {
			
			if ( ! g_unknown ) {
				new player[32], playerNum
				
				if ( get_pcvar_num(pCvar_only_for_dead) )
					get_players(player, playerNum, "cb")
				else
					get_players(player, playerNum, "c")
				
				for ( new i = 0 ; i < playerNum ; i++ )
					client_print(player[i], print_chat, "[Hangman] %s guessed at %c and solved the word.", name, toupper(said[1][0]))
				
				remove_task(999332)
				
				update_hud()
				
				g_hang = 0
				
				set_task(1.0, "show_success", 857385)
			}
			
			else {
				new player[32], playerNum
				
				if ( get_pcvar_num(pCvar_only_for_dead) )
					get_players(player, playerNum, "cb")
				else
					get_players(player, playerNum, "c")
				
				for ( new i = 0 ; i < playerNum ; i++ )
					client_print(player[i], print_chat, "[Hangman] %s guessed correctly at %c.", name, toupper(said[1][0]))
			}
		}
		
		else {
			new player[32], playerNum
			
			if ( get_pcvar_num(pCvar_only_for_dead) )
				get_players(player, playerNum, "cb")
			else
				get_players(player, playerNum, "c")
			
			for ( new i = 0 ; i < playerNum ; i++ )
				client_print(player[i], print_chat, "[Hangman] Sorry %s, the word doesn't contain %s", name, toupper(said[1][0]))
			
			format_guessed_str()
			
			format_unsolved_word()
			
			g_chances_left--
		}
		
		if ( g_chances_left == 0 ) {
			remove_task(999332)
			set_task(1.0, "show_fail", 857385)
		}
		
		return PLUGIN_HANDLED;
	}
	
	return PLUGIN_CONTINUE;
}

public start_hang(word[]) {
	if ( g_hang )
		return 0
	
	if ( ! get_playersnum() ) {
		if ( get_pcvar_num(pCvar_autohang) >= 5 )
			set_task(10.0, "start_hang")
		return PLUGIN_HANDLED
	}
	
	g_chances_left = get_pcvar_num(pCvar_chances)
	
	if ( g_chances_left < 1 )
		return PLUGIN_HANDLED
	
	g_timer = get_pcvar_float(pCvar_hangtimer)
	
	if ( g_timer <= 5.0 )
		return PLUGIN_HANDLED
	
	g_hang = 1
	g_word[0] = 0
	
	if ( strlen(word) && not_in_banned_words(word) )
		copy(g_word, MAX_LEN_OF_WORDS - 1, word)
	else {
		while ( ! not_in_banned_words(g_word) )
			copy(g_word, MAX_LEN_OF_WORDS - 1, g_word_buffer[random_num(0, g_words-1)])
	}
	
	if ( g_curbanned == BANNED_WORDS -1 )
		g_curbanned = 0
	
	copy(Disabled[g_curbanned], MAX_LEN_OF_WORDS - 1, word)
	
	g_curbanned++
	
	clear_guessed()
	
	new player[32], playerNum
	
	if ( get_pcvar_num(pCvar_only_for_dead) )
		get_players(player, playerNum, "cb")
	else
		get_players(player, playerNum, "c")
	
	for ( new i = 0 ; i < playerNum ; i++ ) {
		client_print(player[i], print_chat, "[Hangman] type /guess or a char to guess at ONE character, example: ^"/guess k^" or just ^"k^"")
		client_print(player[i], print_chat, "[Hangman] You can also guess at whole words.")
	}
	
	format_guessed_str()
	
	format_unsolved_word()
	
	set_task(0.25, "update", 999332, "", 0, "b")
	
	set_task(g_timer, "timeout_hang", 999333)
	
	return 1
}

stock last_in_g_guessed() {
	
	new i, size = sizeof g_guessed
	
	while ( i++ < size && g_guessed[i-1][0] != 0 ) {}
	
	return i-1
}

stock update_hud(bool:wordsolved = false) {
	
	if ( ! g_hang )
		return PLUGIN_CONTINUE
	
	new player[32], playerNum
	
	if ( get_pcvar_num(pCvar_only_for_dead) )
		get_players(player, playerNum, "cb")
	else
		get_players(player, playerNum, "c")
	
	set_hudmessage(100, 50, 200, 0.02, 0.2, 1, 0.3, 0.3, 0.0, 0.0, -1)
	
	if ( wordsolved ) {
		for ( new i = 0 ; i < playerNum ; i++ )
			show_hudmessage(player[i], "[Hangman]^n^n%s^n^nAllready guessed:^n%s", g_word, g_guessed_string, g_chances_left, floatround(g_timer))
	}
	else {
		for ( new i = 0 ; i < playerNum ; i++ )
			show_hudmessage(player[i], "[Hangman]^n^n%s^n^nAllready guessed:^n%s^n^nChances left: %d.^nTime left: %d seconds.", g_unsolved_word, g_guessed_string, g_chances_left, floatround(g_timer))
	}
	
	g_timer -= 0.25
	
	return PLUGIN_CONTINUE
}

stock format_unsolved_word() {
	
	new templen = strlen(g_word), len
	
	g_unknown = 0
	
	for ( new i = 0 ; i < templen ; i++ ) {
		if ( is_in_guessed(g_word[i]) )
			len += formatex(g_unsolved_word[len], 2, " %s", toupper(g_word[i]))
		else {
			g_unknown++
			len += formatex(g_unsolved_word[len], 2, " _")
		}
	}
}

stock is_in_guessed(c) {
	
	new size = sizeof g_guessed
	
	new C = toupper(c)
	
	for ( new i = 0 ; i < size ; i++ ) {
		if ( g_guessed[i][0] == C )
			return 1
	}
	
	return 0
}

stock is_in_word(c) {
	
	new len = strlen(g_word)
	
	new C = toupper(c)
	
	while ( len-- ) {
		if ( g_word[len] == C )
			return 1
	}
	
	return 0
}

stock clear_guessed() {
	
	new i, size = sizeof g_guessed
	
	while ( i++ < size && strlen(g_guessed[i-1]) )
		g_guessed[i-1] = ""
}

stock format_guessed_str() {
	
	if ( ! strlen(g_guessed[0]) || is_all_guessed_correct() ) {
		formatex(g_guessed_string, 4, "None")
		return
	}
	
	new first = 1, i, len, size = sizeof g_guessed
	
	while ( i++ < size && strlen(g_guessed[i-1]) ) {
		
		if ( ! is_in_word(g_guessed[i-1][0]) && strlen(g_guessed[i-1]) ) {
			
			if ( first ) {
				len += formatex(g_guessed_string[len], 1, "%s", g_guessed[i-1])
				first = 0
			}
			
			else
				len += formatex(g_guessed_string[len], 3, ", %s", g_guessed[i-1])
		}
	}
}

stock is_all_guessed_correct() {
	
	new i, size = sizeof g_guessed
	
	while ( i++ < size && strlen(g_guessed[i-1]) ) {
		if ( ! is_in_word(g_guessed[i-1][0]) )
			return 0
	}
	
	return 1
}

stock not_in_banned_words(word[]) {
	
	if ( !word[0] )
		return 0;
	
	for ( new i ; i < BANNED_WORDS ; i++ ) {
		if ( equali(word, Disabled[i]) )
			return 0;
	}
	return 1;
}
/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1053\\ f0\\ fs16 \n\\ par }
*/
