2014-11-30 06:17:28 +00:00
--[[
================================================================================================================
== base_chatcommands.lua
== -- Allows maps to use player chat as commands to perform
== -- various functions
================================================================================================================
== Instructions
== -- To add commands:
=~~ Code : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=
chatbase_addcommand ( " commandname " , " Command description " , " command example " )
function chat_commandname ( player , parameter1 , parameter2 , ... )
-- perform some task
end
=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=
== -- The description and example parameters are both optional
== -- Do NOT put the command prefix in either the example or the commandname parameters
== -- The player parameter will always get sent to chat_commandname functions, but the others are optional
== -- Parameters are sent by players in this format !commandname param1 param2 ...
== --
== -- To add player settings:
=~~ Code : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=
chatbase_addplayersetting ( " settingname " , default_value , " Setting description " )
=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=
== -- The description is optional
== --
== -- To get a setting value for a player:
=~~ Code : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=
chatbase_getplayersetting ( player , " settingname " )
=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=
== --
== -- To set a setting value for a player:
=~~ Code : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=
chatbase_setplayersetting ( player , " settingname " , value )
=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=
== --
== -- Settings:
== -- -- The settings below should be copied, pasted, and altered into your maps .lua if you want to
== -- -- change any of them
================================================================================================================
] ] --
-- chat command settings
CHAT_COMMAND_PREFIX = " ! " -- Command prefix, all commands must start with this string
CHAT_COMMAND_HIDECHATSTRING = true -- Determines if the chat string is shown if it executes a command
CHAT_COMMAND_DISABLE_PERIODIC_NOTIFY = false -- If false, the server will notify players that chat commands
-- are enabled for the map ONLY IF non-default chat commands exist
CHAT_COMMAND_PERIODIC_NOTIFY_REPEAT = 0 -- Number of times to repeat the notification (set to -1 for infinite)
CHAT_COMMAND_PERIODIC_NOTIFY_PERIOD = 60 -- Time between notifications (in seconds)
-- theme settings
-- 0 = orange 1 = blue 2 = red 3 = yellow 4 = green
-- 5 = white 6 = black 7 = gray 8 = purple 9 = teal
CHAT_COMMAND_COLOR_MAIN = 0 -- used most often
CHAT_COMMAND_COLOR_HIGHLIGHT1 = 5 -- used to emphasize something
CHAT_COMMAND_COLOR_HIGHLIGHT2 = 5 -- used to emphasize something
CHAT_COMMAND_COLOR_HIGHLIGHT3 = 5 -- used to emphasize something
CHAT_COMMAND_COLOR_ERROR = 2 -- used for error messages
-- chat command debug settings
CHAT_COMMAND_DEBUG = false
CHAT_COMMAND_DEBUG_PREFIX = " [lua-chatcommands] "
--[[
=====================================
== GLOBAL VARS
=====================================
== Do NOT edit these unless you know
== exactly what you ' re doing
=====================================
] ] --
-- chat commands global table
chatbase_commands = { }
chatbase_players = { }
chatbase_settings = { }
chatbase_defaultcommands = { " help " , " disablenotify " }
--[[
=====================================
== CHAT COMMAND FUNCTIONS
=====================================
==
=====================================
] ] --
-------------------------------------
-- Setup
-------------------------------------
function chatbase_addcommand ( command , description , example )
chatbase_debug ( " Adding command " .. tostring ( command ) .. " with desc " .. tostring ( description ) .. " and example " .. tostring ( example ) )
chatbase_commands [ command ] = { }
chatbase_commands [ command ] . description = description
chatbase_commands [ command ] . example = example
end
function chatbase_addplayersetting ( setting , default , description )
chatbase_debug ( " Adding setting " .. tostring ( setting ) .. " with default " .. tostring ( default ) .. " and desc " .. tostring ( description ) )
chatbase_settings [ setting ] = { }
chatbase_settings [ setting ] . default = default
chatbase_settings [ setting ] . description = description
end
-------------------------------------
-- Utilities
-------------------------------------
function chatbase_customcommandsexist ( )
-- check that non-default commands exist
chatbase_debug ( " Checking if custom commands exist " )
local nondefexist = false
for command , values in pairs ( chatbase_commands ) do
local found = false
chatbase_debug ( " Checking command " .. tostring ( command ) )
for i , defcommand in pairs ( chatbase_defaultcommands ) do
chatbase_debug ( " -> Against default command " .. tostring ( defcommand ) )
if defcommand == command then
chatbase_debug ( " Command " .. tostring ( command ) .. " is default " )
found = true
end
end
if not found then
chatbase_debug ( " Command " .. tostring ( command ) .. " is not default " )
nondefexist = true
break ;
end
end
chatbase_debug ( " Custom commands exist: " .. tostring ( nondefexist ) )
return nondefexist ;
end
-------------------------------------
-- Notifications
-------------------------------------
function chatbase_setupnotify ( )
chatbase_debug ( " setupnotify called " )
-- if notifications are completely disabled, return early
if CHAT_COMMAND_DISABLE_PERIODIC_NOTIFY then return end
chatbase_debug ( " setupnotify got past disabled check " )
-- if only default commands exist, then theres no reason to notify
if not chatbase_customcommandsexist ( ) then return end
chatbase_debug ( " setupnotify got past custom commands check " )
-- call a function that will notify anyone that meets the requirements every NOTIFY_PERIOD
AddScheduleRepeating ( " chatbase_notifyenabled " , CHAT_COMMAND_PERIODIC_NOTIFY_PERIOD , chatbase_notifyenabled )
end
-- wait 10 seconds to setup notification, just to be safe that all commands are registered
AddSchedule ( " chatbase_setupnotify " , 10 , chatbase_setupnotify )
function chatbase_notifyenabled ( )
chatbase_debug ( " notifyenabled called " )
-- if notifications are completely disabled, return early
if CHAT_COMMAND_DISABLE_PERIODIC_NOTIFY then return end
chatbase_debug ( " notifyenabled got past disabled check " )
-- if only default commands exist, then theres no reason to notify
if not chatbase_customcommandsexist ( ) then return end
chatbase_debug ( " notifyenabled got past custom commands check " )
-- notify any players that deserve it
for i , v in pairs ( chatbase_players ) do
chatbase_debug ( " checking player ID " .. i )
local player = CastToPlayer ( v.player )
if IsPlayer ( player ) then
chatbase_debug ( " --> IsPlayer " )
-- only notify if they havent set their setting to disable notifications
if v.settings [ " disablenotify " ] ~= true then
chatbase_debug ( " --> disablenotify not true | REPEAT: " .. CHAT_COMMAND_PERIODIC_NOTIFY_REPEAT .. " numtimesnotified: " .. tostring ( v.settings [ " numtimesnotified " ] ) )
-- check repeat type
if CHAT_COMMAND_PERIODIC_NOTIFY_REPEAT == 0 and v.settings [ " numtimesnotified " ] == 0 then
-- only show once
v.settings [ " numtimesnotified " ] = v.settings [ " numtimesnotified " ] + 1
chatbase_notifyplayer ( player )
end
if CHAT_COMMAND_PERIODIC_NOTIFY_REPEAT > 0 and v.settings [ " numtimesnotified " ] <= CHAT_COMMAND_PERIODIC_NOTIFY_REPEAT then
-- repeat a set number of times
v.settings [ " numtimesnotified " ] = v.settings [ " numtimesnotified " ] + 1
chatbase_notifyplayer ( player )
end
if CHAT_COMMAND_PERIODIC_NOTIFY_REPEAT < 0 then
-- repeat infinitely (var is set to a negative number)
v.settings [ " numtimesnotified " ] = v.settings [ " numtimesnotified " ] + 1
chatbase_notifyplayer ( player )
end
end
end
end
end
function chatbase_notifyplayer ( player )
if not IsPlayer ( player ) then chatbase_error ( " function chatbase_notifyplayer: Notifying a nonplayer " ) ; return ; end
ChatToPlayer ( player , " ^ " .. CHAT_COMMAND_COLOR_MAIN .. " Chat commands are enabled for this map. Type " .. CHAT_COMMAND_PREFIX .. " help to see what is available " )
end
-------------------------------------
-- Player Table Functions
-------------------------------------
function chatbase_addplayer ( player )
if not IsPlayer ( player ) then chatbase_error ( " function chatbase_addplayer: Trying to add a nonplayer " ) ; return ; end
-- add an entry for the player
chatbase_players [ player : GetId ( ) ] = { }
chatbase_players [ player : GetId ( ) ] . player = player
chatbase_players [ player : GetId ( ) ] . settings = { }
for setting , values in pairs ( chatbase_settings ) do
chatbase_players [ player : GetId ( ) ] . settings [ setting ] = values.default
end
end
function chatbase_removeplayer ( player )
-- param could be a player or a playerid
if tonumber ( player ) then player = GetPlayerByID ( player ) end
if not IsPlayer ( player ) then chatbase_error ( " function chatbase_removeplayer: Trying to remove a nonplayer " ) ; return ; end
-- clear their entry
chatbase_players [ player : GetId ( ) ] = nil
end
-------------------------------------
-- Player Settings Functions
-------------------------------------
function chatbase_getplayersetting ( player , setting )
-- param could be a player or a playerid
if tonumber ( player ) then player = GetPlayerByID ( player ) end
if not IsPlayer ( player ) then chatbase_error ( " function chatbase_getplayersetting: Trying to get setting of a nonplayer " ) ; return nil ; end
if chatbase_players [ player : GetId ( ) ] ~= nil then
return chatbase_players [ player : GetId ( ) ] . settings [ setting ]
else
chatbase_error ( " function chatbase_getplayersetting: Player not found in the table " ) ;
return nil
end
end
function chatbase_setplayersetting ( player , setting , value )
-- param could be a player or a playerid
if tonumber ( player ) then player = GetPlayerByID ( player ) end
if not IsPlayer ( player ) then chatbase_error ( " function chatbase_setplayersetting: Trying to set setting of a nonplayer " ) ; return false ; end
if chatbase_players [ player : GetId ( ) ] ~= nil then
chatbase_players [ player : GetId ( ) ] . settings [ setting ] = value ;
return true
else
chatbase_error ( " function chatbase_setplayersetting: Player not found in the table " ) ;
return false
end
end
-------------------------------------
-- Debug/Messaging
-------------------------------------
function chatbase_error ( str )
ConsoleToAll ( CHAT_COMMAND_DEBUG_PREFIX .. " [ERROR] " .. str )
end
function chatbase_debug ( str )
if CHAT_COMMAND_DEBUG then ConsoleToAll ( CHAT_COMMAND_DEBUG_PREFIX .. str ) end
end
--[[
=====================================
== DEFAULT COMMAND IMPLEMENTATION
=====================================
==
=====================================
] ] --
chatbase_addcommand ( " help " , " Display a list of all available commands " )
function chat_help ( player )
ChatToPlayer ( player , " ^ " .. CHAT_COMMAND_COLOR_MAIN .. " Chat Commands: " )
for command , values in pairs ( chatbase_commands ) do
local command_text = " ^ " .. CHAT_COMMAND_COLOR_HIGHLIGHT1 .. CHAT_COMMAND_PREFIX .. command
if values.description ~= nil then
command_text = command_text .. " ^ " .. CHAT_COMMAND_COLOR_MAIN .. " - " .. " ^ " .. CHAT_COMMAND_COLOR_HIGHLIGHT2 .. values.description
end
if values.example ~= nil then
command_text = command_text .. " ^ " .. CHAT_COMMAND_COLOR_MAIN .. " (example: " .. CHAT_COMMAND_PREFIX .. values.example .. " ) "
end
ChatToPlayer ( player , command_text )
end
end
if not CHAT_COMMAND_DISABLE_PERIODIC_NOTIFY then
chatbase_addcommand ( " disablenotify " , " Disables the periodic notification that chat commands are enabled " )
function chat_disablenotify ( player )
chatbase_setplayersetting ( player , " disablenotify " , true )
ChatToPlayer ( player , " ^ " .. CHAT_COMMAND_COLOR_MAIN .. " Periodic \" chat commands are enabled \" notifications disabled " )
end
end
--[[
=====================================
== DEFAULT SETTING IMPLEMENTATION
=====================================
==
=====================================
] ] --
chatbase_addplayersetting ( " disablenotify " , false , " Disables periodic notifications that chat commands are enabled " )
chatbase_addplayersetting ( " numtimesnotified " , 0 , " Number of times the player has been notified that chat commands are enabled " )
--[[
=====================================
== CALLBACKS
=====================================
==
=====================================
] ] --
-- player_onchat()
---- handle chat commands
-- save parent player_onchat
local base_player_onchat = player_onchat
function player_onchat ( player , chatstring )
-- call parent onchat function if it exists
if base_player_onchat ~= nil then base_player_onchat ( player , chatstring ) end
local player = CastToPlayer ( player )
-- string.gsub call removes all control characters (newlines, return carriages, etc)
-- string.sub call removes the playername: part of the string, leaving just the message
local message = string.sub ( string.gsub ( chatstring , " %c " , " " ) , string.len ( player : GetName ( ) ) + 3 )
chatbase_debug ( " Message: " .. message )
local prefix = string.sub ( message , 1 , string.len ( CHAT_COMMAND_PREFIX ) )
chatbase_debug ( " Prefix: " .. prefix )
-- if the first character of the string doesn't match the prefix, then we don't care about it
if prefix ~= CHAT_COMMAND_PREFIX then return true ; end
-- strip the prefix character
message = string.sub ( message , 1 + string.len ( CHAT_COMMAND_PREFIX ) )
chatbase_debug ( " Message: " .. message )
-- if there is no message at all, return
if string.match ( message , " %a+ " ) == nil then return true end
-- get command and parameters
local command = string.lower ( string.match ( message , " %a+ " ) )
local paramstring = string.sub ( message , string.len ( command ) + 2 )
local params = explode ( " " , paramstring )
-- loop through all params and convert any numbers to actual numbers
for i , param in pairs ( params ) do
-- tonumber() returns nil if it can't convert to a number
if tonumber ( param ) ~= nil then
param = tonumber ( param )
end
chatbase_debug ( " Param " .. i .. " : " .. param )
end
-- insert the player as the first param always
table.insert ( params , 1 , player )
-- find function to call
local func , finderror = findfunction ( " chat_ " .. command )
if func ~= nil then
if CHAT_COMMAND_DEBUG then ConsoleToAll ( CHAT_COMMAND_DEBUG_PREFIX .. " Function for " .. command .. " found " ) ; end
-- translates to chat_<command>( <arg1>, <arg2>, ... ) e.g. chat_help() or chat_set( "varname", 5 )
func ( unpack ( params ) )
else
ChatToPlayer ( player , " ^ " .. CHAT_COMMAND_COLOR_ERROR .. " Unexpected error while executing command " )
chat_error ( " Command function find error for " .. command .. " ( " .. paramstring .. " ): " .. finderror )
return true
end
if CHAT_COMMAND_HIDECHATSTRING then
return false
else
return true
end
end
-- player_connected()
---- keep track of players
-- save parent player_connected
local base_player_connected = player_connected
function player_connected ( player )
-- call parent onchat function if it exists
if base_player_connected ~= nil then base_player_connected ( player ) end
local player = CastToPlayer ( player )
chatbase_addplayer ( player )
end
-- player_disconnected()
---- keep track of players
-- save parent player_disconnected
local base_player_disconnected = player_disconnected
function player_disconnected ( player )
-- call parent onchat function if it exists
if base_player_disconnected ~= nil then base_player_disconnected ( player ) end
local player = CastToPlayer ( player )
chatbase_removeplayer ( player )
end
--[[
=====================================
== HELPERS
=====================================
==
=====================================
] ] --
-- Find a function with the given string name in the global table
function findfunction ( x )
assert ( type ( x ) == " string " )
local f = _G
for v in x : gmatch ( " [^%.]+ " ) do
if type ( f ) ~= " table " then
return nil , " looking for ' " .. v .. " ' expected table, not " .. type ( f )
end
f = f [ v ]
end
if type ( f ) == " function " then
return f
else
return nil , " expected function, not " .. type ( f )
end
end
-- Explode a string by the given divider
function explode ( div , str )
if ( div == ' ' ) then return false end
local pos , arr = 0 , { }
-- for each divider found
for st , sp in function ( ) return string.find ( str , div , pos , true ) end do
table.insert ( arr , string.sub ( str , pos , st - 1 ) ) -- Attach chars left of current divider
pos = sp + 1 -- Jump past current divider
end
table.insert ( arr , string.sub ( str , pos ) ) -- Attach chars right of last divider
return arr
end