#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
 
#define PLUGIN	"Wall Text"
#define AUTHOR	"stupok"
#define VERSION	"1.09"
 
#define CHAR_WIDTH	12
 
#define MESSAGE_LEN	64
#define BUFFER_LEN	512
 
#define ACCESS_LEVEL ADMIN_KICK
 
new Array:g_aOrigins
new Array:g_aVectors
new Array:g_aMessages
new Array:g_aSaved
 
new g_szConfigsDir[128]
new g_szMapName[64]
new g_szFile[256]
 
new g_iDecalAlpha, g_iDecalAlphaBk, g_iDecalDigit, g_iDecalDigitBk
 
new g_iDecalResetEvent
new g_fwdidPrecacheEvent
 
public plugin_init()
{
	register_plugin( PLUGIN, VERSION, AUTHOR )
 
	register_clcmd( "amx_walltext", "cmd_WallText", ACCESS_LEVEL, "- amx_walltext <Szoveg ami a falra kerul>" )
	register_clcmd( "amx_walltextmenu", "cmd_WallTextMenu", ACCESS_LEVEL, "- Fal szoveg menu" )
	register_clcmd( "say walltextmenu", "cmd_WallTextMenu", ACCESS_LEVEL, "- Fal szoveg menu" )
 
	if( get_user_msgid( "HLTV" ) )
		register_event( "HLTV", "event_NewRound", "a", "1=0", "2=0" )
 
	g_aOrigins = ArrayCreate( 3 )
 
	g_aVectors = ArrayCreate( 3 )
 
	g_aMessages = ArrayCreate( MESSAGE_LEN )
 
	g_aSaved = ArrayCreate()
 
	get_configsdir( g_szConfigsDir, charsmax( g_szConfigsDir ) )
	get_mapname( g_szMapName, charsmax( g_szMapName ) )
 
	formatex( g_szFile, charsmax( g_szFile ), "%s/maps", g_szConfigsDir )
 
	if( !dir_exists( g_szFile ) )
		mkdir( g_szFile )
 
	formatex( g_szFile, charsmax( g_szFile ), "%s/maps/walltext-%s.ini", g_szConfigsDir, g_szMapName )
 
	g_iDecalAlphaBk = engfunc( EngFunc_DecalIndex, "{smscorch2" )
 
	g_iDecalAlpha = engfunc( EngFunc_DecalIndex, "{capsa" )
 
	g_iDecalDigitBk = engfunc( EngFunc_DecalIndex, "{break3" )
 
	g_iDecalDigit = engfunc( EngFunc_DecalIndex, "{small#s0" )
 
	LoadMessagesFromFile()
}
 
public plugin_precache()
{
	g_fwdidPrecacheEvent = register_forward( FM_PrecacheEvent, "forward_PrecacheEvent", 1 )
}
 
public forward_PrecacheEvent( type, const szName[] )
{
	if( equal( szName, "events/decal_reset.sc" ) )
	{
		g_iDecalResetEvent = get_orig_retval()
		unregister_forward( FM_PrecacheEvent, g_fwdidPrecacheEvent, 1 )
	}
}
 
public event_NewRound()
{
	set_task( 0.2, "LoadMessagesFromArray" )
}
 
public client_putinserver( id )
{
	set_task( 3.0, "LoadMessagesFromArray" )
}
 
public cmd_WallText( id )
{
	if( !( get_user_flags( id ) & ACCESS_LEVEL ) )
		return PLUGIN_HANDLED
 
	new szArg[MESSAGE_LEN]
	read_args( szArg, charsmax( szArg ) )
	strtoupper( szArg )
 
	CreateNewMessage( id, szArg )
 
	return PLUGIN_HANDLED
}
 
public cmd_WallTextMenu( id )
{
	if( !( get_user_flags( id ) & ACCESS_LEVEL ) )
		return PLUGIN_HANDLED
 
	new iMenu = menu_create( "Fal szoveg menu:", "menu_HandleMainMenu" )
 
	menu_additem( iMenu, "Uj szoveg", "1" )
	menu_additem( iMenu, "Szoveg mentese", "2" )
	menu_additem( iMenu, "Szoveg torlese", "3" )
 
	if( g_iDecalResetEvent != 0 )
		menu_additem( iMenu, "Refresh Canvas", "4" )
 
	menu_setprop( iMenu, MPROP_EXIT, MEXIT_ALL )
 
	menu_display( id, iMenu, 0 )
 
	return PLUGIN_HANDLED
}
 
public cmd_SaveWallText( id )
{
	if( !( get_user_flags( id ) & ACCESS_LEVEL ) )
		return PLUGIN_HANDLED
 
	new iSize = ArraySize(g_aMessages)
	new szMessage[MESSAGE_LEN]
	new szIndex[8]
 
	new iMenu = menu_create( "Szoveg mentese menu:", "menu_HandleSaveMenu" )
 
	for( new i = 0; i < iSize; i++ )
	{
		if( ArrayGetCell( g_aSaved, i ) )
			continue
 
		ArrayGetString( g_aMessages, i, szMessage, MESSAGE_LEN - 1 )
		num_to_str( i, szIndex, charsmax( szIndex ) )
 
		menu_additem( iMenu, szMessage, szIndex, 0 )
	}
 
	menu_additem( iMenu, "Vissza", "-1", 0 )
 
	menu_setprop( iMenu, MPROP_EXIT, MEXIT_NEVER )
 
	menu_display( id, iMenu, 0 )
 
	return PLUGIN_HANDLED
}
 
public cmd_DeleteWallText( id )
{
	if( !( get_user_flags( id ) & ACCESS_LEVEL ) )
		return PLUGIN_HANDLED
 
	new fh = fopen( g_szFile, "rt" )
 
	if( !fh )
		return PLUGIN_HANDLED
 
	new iLine
	new szIndex[8]
	new szBuffer[BUFFER_LEN]
 
	new iMenu = menu_create( "Mentett szoveg torlese:", "menu_HandleDeleteMenu" )
 
	while( !feof( fh ) )
	{
		fgets( fh, szBuffer, charsmax( szBuffer ) )
 
		if( ExtractMessage( szBuffer ) )
		{
			num_to_str( iLine, szIndex, charsmax( szIndex) )
 
			menu_additem( iMenu, szBuffer, szIndex, 0 )
			szBuffer[0] = 0
		}
 
		iLine++
	}
 
	fclose( fh )
 
	menu_additem( iMenu, "Back", "-1", 0 )
 
	menu_setprop( iMenu, MPROP_EXIT, MEXIT_NEVER )
 
	menu_display( id, iMenu, 0 )
 
	return PLUGIN_HANDLED
}
 
public menu_HandleMainMenu( id, menu, item )
{
	if( item == MENU_EXIT )
	{
		menu_destroy( menu )
		return PLUGIN_HANDLED
	}
 
	new iAccess, szInfo[8], szName[32], iCallBack
	menu_item_getinfo( menu, item, iAccess, szInfo, charsmax( szInfo ), szName, charsmax( szName ), iCallBack )
 
	switch( str_to_num( szInfo ) )
	{
		case 1:
		{	
			client_cmd( id, "messagemode amx_walltext" )
			cmd_WallTextMenu( id )
		}
		case 2:
		{
			menu_destroy( menu )
			cmd_SaveWallText( id )
		}
		case 3:
		{
			menu_destroy( menu )
			cmd_DeleteWallText( id )
		}
		case 4:
		{
			engfunc( EngFunc_PlaybackEvent, FEV_GLOBAL, 0, g_iDecalResetEvent )
			cmd_WallTextMenu( id )
			set_task( 0.2, "LoadMessagesFromArray" )
		}
	}
 
	return PLUGIN_HANDLED
}
 
public menu_HandleSaveMenu( id, menu, item )
{
	if( item == MENU_EXIT )
	{
		menu_destroy( menu )
		cmd_WallTextMenu( id )
		return PLUGIN_HANDLED
	}
 
	new szMessage[MESSAGE_LEN], szIndex[8]
	new iAccess, iCallBack
 
	menu_item_getinfo( menu, item, iAccess, szIndex, charsmax( szIndex ), szMessage, charsmax( szMessage ), iCallBack )
 
	new iIndex = str_to_num( szIndex )
 
	if( iIndex == -1 )
	{
		menu_destroy( menu )
		cmd_WallTextMenu( id )
		return PLUGIN_HANDLED
	}
 
	WriteToFile( iIndex )
 
	client_print( id, print_chat, "* Hozzaadva a szoveg '%s' '%s'", szMessage, g_szFile )
 
	cmd_SaveWallText( id )
 
	return PLUGIN_HANDLED
}
 
public menu_HandleDeleteMenu( id, menu, item )
{
	if( item == MENU_EXIT )
	{
		menu_destroy( menu )
		cmd_WallTextMenu( id )
		return PLUGIN_HANDLED
	}
 
	new szMessage[MESSAGE_LEN], szIndex[8]
	new iAccess, iCallBack
 
	menu_item_getinfo( menu, item, iAccess, szIndex, charsmax( szIndex ), szMessage, charsmax( szMessage ), iCallBack )
 
	if( str_to_num( szIndex ) == -1 )
	{
		menu_destroy( menu )
		cmd_WallTextMenu( id )
		return PLUGIN_HANDLED
	}
 
	new fh = fopen( g_szFile, "rt" )
 
	if( !fh )
		return PLUGIN_HANDLED
 
	new szBuffer[BUFFER_LEN]
	new iLine
 
	while( !feof( fh ) )
	{
		fgets( fh, szBuffer, charsmax( szBuffer ) )
 
		if( ExtractMessage( szBuffer ) )
		{
			if( equal( szBuffer, szMessage ) )
			{
				fclose( fh )
				write_file( g_szFile, "", iLine )
 
				client_print( id, print_chat, "* Torolve a '%s' uzenet '%s'", szMessage, g_szFile )
 
				cmd_DeleteWallText( id )
 
				ArrayClear( g_aOrigins )
				ArrayClear( g_aVectors )
				ArrayClear( g_aMessages )
				ArrayClear( g_aSaved )
 
				LoadMessagesFromFile()
 
				return PLUGIN_HANDLED
			}
			szBuffer[0] = 0
		}
 
		iLine++
	}
 
	fclose( fh )
 
	return PLUGIN_HANDLED
}
 
public LoadMessagesFromArray()
{
	new iSize = ArraySize( g_aOrigins )
 
	new Float:fOrigin[3]
	new Float:fVector[3]
	new szMessage[MESSAGE_LEN]
 
	for( new i = 0; i < iSize; i++ )
	{
		ArrayGetArray( g_aOrigins, i, fOrigin )
		ArrayGetArray( g_aVectors, i, fVector )
		ArrayGetString( g_aMessages, i, szMessage, charsmax( szMessage ) )
 
		DrawMessage( szMessage, fOrigin, fVector )
	}
}
 
public LoadMessagesFromFile()
{
	new fh = fopen( g_szFile, "rt" )
 
	if( !fh )
		return PLUGIN_HANDLED
 
	new szBuffer[BUFFER_LEN]
	new szPart[BUFFER_LEN]
	new Float:fOrigin[3]
	new Float:fVector[3]
	new szMessage[MESSAGE_LEN]
 
	while( !feof( fh ) )
	{
		fgets( fh, szBuffer, charsmax( szBuffer ) )
		if( strlen(szBuffer) < 13 ) continue
 
		strtok( szBuffer, szPart, charsmax( szPart ), szBuffer, charsmax( szBuffer ), ';', 1 )
		fOrigin[0] = str_to_float( szPart )
		strtok( szBuffer, szPart, charsmax( szPart ), szBuffer, charsmax( szBuffer ), ';', 1 )
		fOrigin[1] = str_to_float( szPart )
		strtok( szBuffer, szPart, charsmax( szPart ), szBuffer, charsmax( szBuffer ), ';', 1 )
		fOrigin[2] = str_to_float( szPart )
 
		strtok( szBuffer, szPart, charsmax( szPart ), szBuffer, charsmax( szBuffer ), ';', 1 )
		fVector[0] = str_to_float( szPart )
		strtok( szBuffer, szPart, charsmax( szPart ), szBuffer, charsmax( szBuffer ), ';', 1 )
		fVector[1] = str_to_float( szPart )
		strtok( szBuffer, szPart, charsmax( szPart ), szMessage, charsmax( szMessage ), ';', 1 )
		fVector[2] = str_to_float( szPart )
 
		replace( szMessage, charsmax( szMessage ), "^n", "" )
 
		if( file_exists( szMessage ) )
		{
			new fh2 = fopen( szMessage, "rt" )
 
			if( fh2 )
			{
				fgets( fh2, szMessage, charsmax( szMessage ) )
				fclose( fh2 )
			}
		}
 
		strtoupper( szMessage )
 
		ArrayPushArray( g_aOrigins, fOrigin )
		ArrayPushArray( g_aVectors, fVector )
 
		ArrayPushString( g_aMessages, szMessage )
 
		ArrayPushCell( g_aSaved, 1 )
 
		DrawMessage( szMessage, fOrigin, fVector )
	}
 
	fclose( fh )
 
	return PLUGIN_HANDLED
}
 
ExtractMessage( szBuffer[BUFFER_LEN] )
{
	new iLen = strlen( szBuffer )
	new iSemicolonCount = 0
 
	for( new i = 0; i < iLen; i++ )
	{
		if( szBuffer[i] == ';' )
		{
			iSemicolonCount++
		}
 
		if( iSemicolonCount == 6 )
		{
			copy( szBuffer, charsmax( szBuffer ), szBuffer[i+1] )
			replace(szBuffer, charsmax( szBuffer ), "^n", "")
			return 1
		}
	}
 
	return 0
}
 
WriteToFile( iIndex )
{
	new Float:fOrigin[3]
	new Float:fVector[3]
	new szMessage[MESSAGE_LEN]
 
	ArrayGetArray( g_aOrigins, iIndex, fOrigin )
	ArrayGetArray( g_aVectors, iIndex, fVector )
	ArrayGetString( g_aMessages, iIndex, szMessage, charsmax( szMessage ) )
 
	new szBuffer[BUFFER_LEN]
 
	formatex( szBuffer, charsmax( szBuffer ), "%f;%f;%f;%f;%f;%f;%s",
	fOrigin[0], fOrigin[1], fOrigin[2],
	fVector[0], fVector[1], fVector[2],
	szMessage )
 
	write_file( g_szFile, szBuffer, -1 )
 
	ArraySetCell( g_aSaved, iIndex, 1 )
}
 
DrawMessage( szMessage[MESSAGE_LEN], Float:fAimOrigin[3], Float:fTextVector[3] )
{
	new Float:fOffset[3]
 
	new iLen = strlen( szMessage )
 
	fOffset[0] = 0.0
	fOffset[1] = 0.0
	fOffset[2] = 0.0
 
	for( new i = 0; i < iLen; i++ )
	{	
		if( isalpha( szMessage[i] ) )
		{
			DrawDecal( fAimOrigin[0] + fOffset[0], fAimOrigin[1] + fOffset[1], fAimOrigin[2] + fOffset[2], g_iDecalAlphaBk )
		}
		else if( szMessage[i] == ',' )
		{
			fOffset[0] = 0.0
			fOffset[1] = 0.0
			fOffset[2] -= 23.0
		}
 
		fOffset[0] += fTextVector[0]
		fOffset[1] += fTextVector[1]
	}
 
	fOffset[0] = 0.0
	fOffset[1] = 0.0
	fOffset[2] = 0.0
 
	for( new i = 0; i < iLen; i++ )
	{	
		if( '0' <= szMessage[i] <= '9' )
		{
			DrawDecal( fAimOrigin[0] + fOffset[0], fAimOrigin[1] + fOffset[1], fAimOrigin[2] + fOffset[2], g_iDecalDigitBk )
		}
		else if( szMessage[i] == ',' )
		{
			fOffset[0] = 0.0
			fOffset[1] = 0.0
			fOffset[2] -= 23.0
		}
 
		fOffset[0] += fTextVector[0]
		fOffset[1] += fTextVector[1]
	}
 
	fOffset[0] = 0.0
	fOffset[1] = 0.0
	fOffset[2] = 0.0
 
	for( new i = 0; i < iLen; i++ )
	{	
		if( isalpha( szMessage[i] ) )
		{
			DrawDecal( fAimOrigin[0] + fOffset[0], fAimOrigin[1] + fOffset[1], fAimOrigin[2] + fOffset[2], g_iDecalAlpha + 'A' - szMessage[i] )
		}
		else if( szMessage[i] == ',' )
		{
			fOffset[0] = 0.0
			fOffset[1] = 0.0
			fOffset[2] -= 23.0
		}
 
		fOffset[0] += fTextVector[0]
		fOffset[1] += fTextVector[1]
	}
 
	fOffset[0] = 0.0
	fOffset[1] = 0.0
	fOffset[2] = 0.0
 
	for( new i = 0; i < iLen; i++ )
	{	
		if( '0' <= szMessage[i] <= '9' )
		{
			DrawDecal( fAimOrigin[0] + fOffset[0], fAimOrigin[1] + fOffset[1], fAimOrigin[2] + fOffset[2], g_iDecalDigit + '0' - szMessage[i] )
		}
		else if( szMessage[i] == ',' )
		{
			fOffset[0] = 0.0
			fOffset[1] = 0.0
			fOffset[2] -= 23.0
		}
 
		fOffset[0] += fTextVector[0]
		fOffset[1] += fTextVector[1]
	}
}
 
CreateNewMessage( id, szMessage[MESSAGE_LEN] )
{
	new Float:fAimOrigin[3]
	new Float:fPlayerOrigin[3]
 
	new Float:fAimVector[3]
	new Float:fNormalVector[3]
	new Float:fTextVector[3]
 
	pev( id, pev_v_angle, fAimVector )
 
	angle_vector( fAimVector, ANGLEVECTOR_FORWARD, fAimVector )
 
	pev( id, pev_origin, fPlayerOrigin )
 
	fAimVector[0] = fAimVector[0] * 9999.0 + fPlayerOrigin[0]
	fAimVector[1] = fAimVector[1] * 9999.0 + fPlayerOrigin[1]
	fAimVector[2] = fAimVector[2] * 9999.0 + fPlayerOrigin[2]
 
	new iTr = create_tr2()
	engfunc( EngFunc_TraceLine, fPlayerOrigin, fAimVector, IGNORE_MONSTERS, id, iTr )
	get_tr2( iTr, TR_vecEndPos, fAimOrigin )
	get_tr2( iTr, TR_vecPlaneNormal, fNormalVector )
	free_tr2( iTr )
 
	vector_to_angle( fNormalVector, fTextVector )
 
	angle_vector( fTextVector, ANGLEVECTOR_RIGHT, fTextVector )
 
	fTextVector[0] *= -1.0 * CHAR_WIDTH
	fTextVector[1] *= -1.0 * CHAR_WIDTH
	fTextVector[2] *= -1.0 * CHAR_WIDTH
 
	DrawMessage( szMessage, fAimOrigin, fTextVector )
 
	ArrayPushArray( g_aOrigins, fAimOrigin )
	ArrayPushArray( g_aVectors, fTextVector )
 
	remove_quotes( szMessage )
	replace( szMessage, charsmax( szMessage ), "^n", "" )
	ArrayPushString( g_aMessages, szMessage )
 
	ArrayPushCell( g_aSaved, 0 )
}
 
DrawDecal( Float:x, Float:y, Float:z, tid )
{
	message_begin( MSG_BROADCAST, SVC_TEMPENTITY )
	if( tid  > 255 )
	{
		tid -= 255
		write_byte( TE_WORLDDECALHIGH )
	}
	else
	{
		write_byte( TE_WORLDDECAL )
	}
	engfunc( EngFunc_WriteCoord, x )
	engfunc( EngFunc_WriteCoord, y )
	engfunc( EngFunc_WriteCoord, z )
	write_byte( tid )
	message_end()
}