PtokaX forum

Archive => Archived 5.0 boards => Finished Scripts => Topic started by: Fangs404 on 28 April, 2005, 00:32:53

Title: say command
Post by: Fangs404 on 28 April, 2005, 00:32:53
this is a fun little command that ops can use to make people say things in mainchat.  ynhub had the feature, and it was really funny sometimes, so i thought i'd write a script that does the same thing.

example:
type "!say nick message"
and you'll see
"[17:31] message"
in the mainchat.

-- Say v1.0
-- by Fangs404
-- last modified 4/27/05
-- tested with PtokaX 0.3.3.0 build 17.03

sBot = frmHub:GetHubBotName()
tPrefixes = frmHub:GetPrefixes()

function ChatArrival(user, sData)
local s,e,sCmd,sNick,sMsg = string.find(sData, "^%b<>%s*(%S+)%s*(%S*)%s*(.*)|")
if (not user.bOperator) or (not isSayCmd(sCmd)) then
return
end
if sNick == "" then
SendToNick(user.sName, "<"..sBot.."> ".."Please provide a nick to use the say command.")
return 1
elseif sMsg == "" then
SendToNick(user.sName, "<"..sBot.."> ".."Please enter a message for "..sNick.." to say.")
return 1
end
SendToAll("<"..sNick.."> "..sMsg)
return 1
end

function isSayCmd(sCmd)
for index in tPrefixes do
if sCmd == (tPrefixes[index].."say") then
return 1
end
end
return
end
Title:
Post by: Fangs404 on 28 April, 2005, 01:46:00
fixed up some stuff and reorganized the code.

-- Say v1.1
-- by Fangs404
-- last modified 4/27/05
-- tested with PtokaX 0.3.3.0 build 17.03

sBot = frmHub:GetHubBotName()
tPrefixes = frmHub:GetPrefixes()

function ChatArrival(user, sData)
local s,e,sCmd,sNick,sMsg = string.find(sData, "^%b<>%s*(%S+)%s*(%S*)%s*(.*)|")
if (not user.bOperator) or (not isSayCmd(sCmd)) then
return
end
if (not isValidSayCmd(user, sNick, sMsg)) then
return 1
end
SendToAll(sNick, sMsg)
return 1
end

function isValidSayCmd(user, sNick, sMsg)
if string.len(sNick) == 0 then
user:SendData(sBot, "Please provide a nick to use the say command.")
return
elseif string.len(sMsg) == 0 then
user:SendData(sBot, "Please enter a message for "..sNick.." to say.")
return
end
return 1
end

function isSayCmd(sCmd)
for index in tPrefixes do
if sCmd == (tPrefixes[index].."say") then
return 1
end
end
return
end
Title:
Post by: Fangs404 on 28 April, 2005, 10:36:04
yay for more generic code.  :)

-- Say v1.2
-- by Fangs404
-- last modified 4/28/05
-- tested with PtokaX 0.3.3.0 build 17.03

sBot = frmHub:GetHubBotName()
tPrefixes = frmHub:GetPrefixes()

function ChatArrival(user, sData)
local s,e,sCmd,sNick,sMsg = string.find(sData, "^%b<>%s*(%S+)%s*(%S*)%s*(.*)|")
if (not user.bOperator) or (not isValidCmd(sCmd, "say")) then
return
end
if (not isValidSayCmd(user, sNick, sMsg)) then
return 1
end
SendToAll(sNick, sMsg)
return 1
end

function isValidSayCmd(user, sNick, sMsg)
if string.len(sNick) == 0 then
user:SendData(sBot, "Please provide a nick to use the say command.")
return
elseif string.len(sMsg) == 0 then
user:SendData(sBot, "Please enter a message for "..sNick.." to say.")
return
end
return 1
end

function isValidCmd(sCurCmd, sNeedCmd)
for index in tPrefixes do
if sCurCmd == (tPrefixes[index]..sNeedCmd) then
return 1
end
end
return
end
Title:
Post by: wegface on 28 April, 2005, 11:34:26
Nice one Fangs! Just what i was after. Good fun. That was best thing about Ynhub hahahahaa.
Title:
Post by: Herodes on 28 April, 2005, 11:46:53
haven't tested ... but wouldn't this do exactly the same thing ?
function ChatArrival( user, data )

local s,e, nick, msg = string.find( data, "^%b<>%s*[%"..table.concat(frmHub:GetPrefixes(), "%").."]say%s+(%S+)%s+(.+)|$")
if nick then
SendToAll( nick, msg )
return 1;
end

end
Title:
Post by: Fangs404 on 29 April, 2005, 00:46:13
QuoteOriginally posted by Herodes
haven't tested ... but wouldn't this do exactly the same thing ?
function ChatArrival( user, data )

local s,e, nick, msg = string.find( data, "^%b<>%s*[%"..table.concat(frmHub:GetPrefixes(), "%").."]say%s+(%S+)%s+(.+)|$")
if nick then
SendToAll( nick, msg )
return 1;
end

end

that does work, but it's not generic enough for me to be able to put in error messages.  i need to make sure that the op has typed !say rather than !topic, and your code doesn't allow for that.

local s,e,sCmd,sNick,sMsg = string.find(sData, "^%b<>%s+(["..table.concat(frmHub:GetPrefixes()).."])(%S+)%s+(%S+)%s+(.+)|")
seems like it should work, but it won't assign the command to sCmd.
Title:
Post by: Herodes on 29 April, 2005, 01:10:20
Just trying to give a concept with the script lines posted .. there is no use for 3 global functions for this kind of script..

This is a more "generic" version ..
function ChatArrival( user, data )

local s,e, args = string.find( string.sub( data,1, -1),  "^%b<>%s+[%"..table.concat(frmHub:GetPrefixes(), "%").."]say%s+(.+)|$")
if args then
local s,e, nick, msg = string.find( args, "^(%S+)%s*(.*)")
if (not nick) or (not msg) or (string.len(msg) == 0) then
user:SendData( frmHub:GetHubBotName(), "Syntax Error Use : !say " );
return 1;
end
SendToAll( nick, msg ) return 1;
end

end
Title:
Post by: Fangs404 on 29 April, 2005, 04:18:00
i redid a lot of mine.  i'm going to keep it broken up into 2 separate functions because the isValidCmd function comes in handy in practically all scripts, so it's nice to keep it generic.

-- Say v1.3
-- by Fangs404
-- last modified 4/28/05
-- tested with PtokaX 0.3.3.0 build 17.03

sBot = frmHub:GetHubBotName()
tPrefixes = frmHub:GetPrefixes()

function ChatArrival(user, sData)
local s,e,sCmd,sNick,sMsg = string.find(sData, "^%b<>%s*(%S*)%s*(%S*)%s*(.*)|")
if user.bOperator and isValidCmd(sCmd, "say") then
if sNick == "" then
user:SendData(sBot, "Please provide a nick to use the say command.")
return 1
elseif sMsg == "" then
user:SendData(sBot, "Please enter a message for "..sNick.." to say.")
return 1
end
SendToAll(sNick, sMsg)
return 1
end
end

function isValidCmd(sCurCmd, sNeedCmd)
for index in tPrefixes do
if sCurCmd == (tPrefixes[index]..sNeedCmd) then
return 1
end
end
end
Title:
Post by: Herodes on 29 April, 2005, 12:19:39
QuoteOriginally posted by Fangs404
i redid a lot of mine.  i'm going to keep it broken up into 2 separate functions because the isValidCmd function comes in handy in practically all scripts, so it's nice to keep it generic.
Though it is a simple way of doing it by using the isValidCmd function, it is much more simple to use a regexp to do it.

The way i propose uses :
- one Api call,
- one lua table lib function call,
- one string.find with regexp.
- two concatations ( .. )

The isValidCmd function uses:
- two global vars ( tPrefixes , isValidCmd [function] ),
- an iterator ( for ... do ... end )
- an expression ( == )
- a concatation ( .. )

The trade off is minimal but I like to keep it compact ..
Title:
Post by: Fangs404 on 29 April, 2005, 22:01:29
QuoteOriginally posted by Herodes
Though it is a simple way of doing it by using the isValidCmd function, it is much more simple to use a regexp to do it.

The way i propose uses :
- one Api call,
- one lua table lib function call,
- one string.find with regexp.
- two concatations ( .. )

The isValidCmd function uses:
- two global vars ( tPrefixes , isValidCmd [function] ),
- an iterator ( for ... do ... end )
- an expression ( == )
- a concatation ( .. )

The trade off is minimal but I like to keep it compact ..
this is an interesting point.  in terms of run time and big O, ours require the same big O - O(N).  keep in mind that behind the scenes, the table.concat function is just a simple loop that combines the elements together.

in terms of space, though, my way requires only one global variable and one function call, the method to retrieve the prefixes only occurs once in my code per session.

theoretically, though, our methods will have essentially the same runtime and space requirements.
Title:
Post by: Herodes on 30 April, 2005, 00:14:02
QuoteOriginally posted by Fangs404
in terms of run time and big O, ours require the same big O - O(N).
hmm .. could you be more clear on that ..
QuoteOriginally posted by Fangs404
keep in mind that behind the scenes, the table.concat function is just a simple loop that combines the elements together.
yep.. done in pure C .. so its impossible that a for .. do *multiple concatations" end is quicker..
QuoteOriginally posted by Fangs404
in terms of space, though, my way requires only one global variable and one function call, the method to retrieve the prefixes only occurs once in my code per session.
Nowhere near in fact. There are no global variables to take up space in the mem in the way I propose, while in the isValidCmd method there are two ( a function and a table ). also the pattern for the pattern matching is also compiled once per session .. exactly as yours.

QuoteOriginally posted by Fangs404
theoretically, though, our methods will have essentially the same runtime and space requirements.
In fact that is the point y I am commenting this post right now .. mine uses cpu while giving up mem, while, the method you propose takes mem to provide for cpu time .. but since there isn't any large amount of data involved and that this data isn't needed later in the script logic, I think that the tip scales to using the cpu..
Title:
Post by: Fangs404 on 30 April, 2005, 02:08:23
QuoteOriginally posted by Herodes
hmm .. could you be more clear on that ..
big O is a programming concept that tells the programmer the approximate run-time cost a program or chunk of code will cost.  O(N) means it has a linear runtime - for loops always take a runtime of O(N).  nested for loops, though, will use O(N^2).  that's an extremely abbreviated version and is better taught in a classroom.  you can google it if you'd like to know more - google "big o."

Quoteyep.. done in pure C .. so its impossible that a for .. do *multiple concatations" end is quicker..
how is it impossible?  regardless of the programming language LUA is implemented in, there's no reason to expect a for loop to take longer than a concat operation which is, under the hood, almost guaranteed to be implemented with a for loop.

QuoteNowhere near in fact. There are no global variables to take up space in the mem in the way I propose, while in the isValidCmd method there are two ( a function and a table ). also the pattern for the pattern matching is also compiled once per session .. exactly as yours.
sure your function will be calculated once per session, but you call the GetPrefixes function each time.  i haven't looked at how LUA is implemented or compiled, but i'd be willing to bet that your function will be calling GetPrefixes every single time a new mainchat message appears.  mine only calls it once.  like i said, though, i could be wrong because i haven't tried it, yet.  it'd be really easy to test.

QuoteIn fact that is the point y I am commenting this post right now .. mine uses cpu while giving up mem, while, the method you propose takes mem to provide for cpu time .. but since there isn't any large amount of data involved and that this data isn't needed later in the script logic, I think that the tip scales to using the cpu..
again, this depends on how LUA is implemented.  in fact, i'm going to go test it right now.  i know for a fact because i've tested mine, that mine only calls GetPrefixes once (each time the script is reloaded).
Title:
Post by: Fangs404 on 30 April, 2005, 02:13:29
yeah, i was right.  your method calls GetPrefixes at each call, so yours does a lot more work than mine does to find out if it's a valid command.  i did this test by calling *say with * not listed in the accepted prefixes under the options menu.  then, i added in the * prefix, and without restarting the script, i tried *say , and it worked.

personally, i think the cost of calling GetPrefixes for every single mainchat message is greater than that of the memory used to store the few acceptable prefixes in a global variable and reference them.
Title:
Post by: Optimus on 30 April, 2005, 12:32:47
-- Say v1.3
-- by Fangs404
-- last modified 4/28/05
-- tested with PtokaX 0.3.3.0 build 17.03
-- Touched by Optimus for better performence

sBot = frmHub:GetHubBotName()
tPrefixes = {}

Main = function()
for a,b in pairs(frmHub:GetPrefixes()) do tPrefixes[b] = 1 end
end

function ChatArrival(user, sData)
local s,e,sPrefix,sCmd,sNick,sMsg = string.find(sData, "%b<>%s*(%S)(%S+)%s*(%S*)%s*(.*)|")
if sPrefix and tPrefixes[sPrefix] then
if user.bOperator and sCmd == "say" then
if sNick == "" then
user:SendData(sBot, "Please provide a nick to use the say command.")
elseif sMsg == "" then
user:SendData(sBot, "Please enter a message for "..sNick.." to say.")
else
SendToAll(sNick, sMsg)
end return 1
end
end
end
I couldn't refuse to give it my own try, this is what i had in mind.

- Optimus
Title:
Post by: Herodes on 02 May, 2005, 20:54:38
hmm.. maybe its my personal taste to keep things as compact as possible .. I am convinced about the call-each-time issue .. but I really think it makes for making clear the objectives of scripts rather than their functions. good to have educated ppl in programming langs in here .. as it has always been ;)
Title:
Post by: Optimus on 02 May, 2005, 21:25:51
Well must be a matter of taste, i would prefer mine cause hashing the prefix is faster then looping it.

so i prefer the loop in main function and hash the rest of commands.

- Optimus
Title:
Post by: Herodes on 03 May, 2005, 12:06:51
Just hit me .. isn't this an even better way to do it ?
sBot = frmHub:GetHubBotName()

function Main()
pCmd = "[%"..table.concat( frmHub:GetPrefixes(), "%").."]"
end

function ChatArrival(user, sData)
if user.bOperator then
local s,e, sPrefix, sCmd, sNick, sMsg = string.find( string.sub( sData, 1, -2 ), "%b<>%s*"..pCmd.."(%S+)%s*(%S*)%s*(.*)")
if sCmd == "say" then
if sNick == "" then
user:SendData(sBot, "Please provide a nick to use the say command."); return 1;
elseif sMsg == "" then
user:SendData(sBot, "Please enter a message for "..sNick.." to say."); return 1;
end
SendToAll(sNick, sMsg); return 1;
end
end
end
Title:
Post by: Optimus on 03 May, 2005, 13:18:39
Yups verry nice