SRL Archive - Other Scripts

TootIRCBot v3


Tootoot222

2009-02-08 08:41:53

Yes! This is my IRC bot that I made! (I based it off of yakman's IScarC)

Have fun!

(This requires SCAR 3.15+, it now has Explode and Implode within the script (if you're using 3.20 you can take them out, as it will make it a little faster))

program TootIRCv3;

const
//Static const can be used within the script, and to set other values
IRC_Static_JoinChan = '#SRL';
IRC_Static_Username = '';
IRC_Static_Realname = '';
IRC_Static_NickServ = '';
IRC_Static_RecoverWord = '';
IRC_Static_Server = 'irc.freenode.net';
IRC_Static_Port = 6665;
IRC_Static_AutoJoin = True;

//Default values should NEVER be used within the script, except to set other values.
//These are used for inital values that will be changed during runtime
//(I.E. the QuitWord, if the MasterNick wants to change that, they can;
//also, the MasterNick can be changed, I.E. you wanna give someone else a try with the bot)
IRC_Default_MasterNick = '';
IRC_Default_JoinNick1 = '';
IRC_Default_JoinNick2 = '';

CRLF = #13#10;

//{$DEFINE Safe}

type
TMessage = record
Nick, User, Host, Sender, Command, Param, TheMessage, WholeLineData: String;
end;

type
TMethod = record
Declaration, Creator, Description, FileIn: String;
end;

var
TheConnection: Integer;
IRC_CurrentServer, IRC_MasterNick, IRC_CurrentNick: String;
IRC_BanList, SRL_Lines: array of String;
Locked, Quitting: Boolean;

function GetOcc(SubStr, S: String): Integer;
var
I: Integer;
begin
Result:= -1;
repeat
I:= PosEx(SubStr, S, I + Length(SubStr));
Result:= Result + 1;
until(I < 1);
end;

function Explode(Seperator, S: String): TStringArray;
var
I: Integer;
begin
S:= S + Seperator;
SetLength(Result, GetOcc(Seperator, S));
for I:= 0 to High(Result) do
begin
Result[I]:= Copy(S, 1, Pos(Seperator, S) - 1);
Delete(S, 1, (Pos(Seperator, S) - 1) + Length(Seperator));
end;
end;

function Implode(Glue: String; Pieces: TStringArray): String;
var
I: Integer;
begin
for I:= 0 to High(Pieces) do
Result:= Result + Pieces[I] + Glue;
Result:= Copy(Result, 1, Length(Result) - Length(Glue));
end;

procedure ConnectToServer(Host: String; Port: Integer);
begin
TheConnection:= OpenConnection(Host, Port, 9999);
end;

function Timestamp: String;
var
H, M, S, MS: Word;
begin
DecodeTime(Time, H, M, S, MS);
Result:= '[' + Padz(IntToStr(H), 2) + ':' + Padz(IntToStr(M), 2) + ':' + Padz(IntToStr(S), 2) + ':' + Padz(IntToStr(MS), 3) + ']';
end;

procedure OutputMessage(CMessage: TMessage; Mes: String);
var
Output: String;
H, M, S, MS: Word;
begin
with CMessage do
begin
if(not(Mes = '')) then
Output:= Mes
else
case Command of
'PRIVMSG': Output:= Param + ': <' + Nick + '> ' + TheMessage;
end;
end;
DecodeTime(Time, H, M, S, MS);
Writeln(Timestamp + ' ' + Output);
end;

procedure SendData(Data: String);
var
MM: TMessage;
begin
if(not(TheConnection < 0)) then
begin
SendConnectionData(TheConnection, Data + CRLF);
OutputMessage(MM, '-> ' + Data);
end;
end;

function InStr(SubStr, S: String): Boolean;
begin
Result:= Pos(SubStr, S) > 0;
end;

function NextToken(var S: String; SubStr: String): String; //pwns yakman's ;)
begin
Result:= #0;
if(Pos(SubStr, S) < 1) then
Exit;
Result:= Copy(S, 1, Pos(SubStr, S) - 1);
Delete(S, 1, Length(Result) + Length(SubStr));
end;

function IsNumber(S: String): Boolean;
var
X: Integer;
begin
Result:= True;
try
X:= StrToInt(S);
if(X = -1) then
if(not(S = '-1')) then
Result:= False;
except
Result:= False;
end;
end;

function InStrArrEx(S: String; StrArr: TStringArray): Integer; //returns where it was found, -1 if not found
begin
for Result:= High(StrArr) downto 0 do
if(Lowercase(StrArr[Result]) = Lowercase(S)) then
Exit;
end;

function MergeArrays(A1, A2: TStringArray): TStringArray;
var
I, L: Integer;
begin
L:= High(A1);
SetLength(Result, L + Length(A2) + 1);
for I:= 0 to L do
Result[I]:= A1[I];
for I:= L + 1 to High(Result) do
Result[I]:= A2[I - L - 1];
end;

procedure LoadBanList;
var
I: Integer;
begin
I:= 0;
repeat
SetArrayLength(IRC_BanList, I + 1);
IRC_BanList[I]:= ReadINI('BANLIST', 'B' + IntToStr(I), ScriptPath + 'TootIRCv3.ini');
if(IRC_BanList[I] = '') then
Break;
I:= I + 1;
until(False);
SetArrayLength(IRC_BanList, I);
end;

procedure SaveBanList;
var
I, II, X: Integer;
S: String;
begin
X:= OpenFile(ScriptPath + 'TootIRCv3.ini', False);
ReadFileString(X, S, FileSize(X));
CloseFile(X);
for I:= 0 to GetOcc(#10 + 'B', S) - 1 do
DeleteINI('BANLIST', 'B' + IntToStr(I), ScriptPath + 'TootIRCv3.ini');
II:= 0;
for I:= 0 to High(IRC_BanList) do
begin
WriteINI('BANLIST', 'B' + IntToStr(II), IRC_BanList[I], ScriptPath + 'TootIRCv3.ini');
if(IRC_BanList[I] = '') then
Continue;
II:= II + 1;
end;
end;

procedure AddToBanList(Nicks, ChannelList: TStringArray);
var
I, II, III: Integer;
begin
for I:= 0 to High(Nicks) do
begin
if(not(InStrArr(Nicks[I], IRC_BanList, False))) then
begin
SendData('PRIVMSG ' + Nicks[I] + ' :' + Nicks[I] + ': You have been banned from using this bot.');
II:= InStrArrEx('', IRC_BanList);
if(II >= 0) then
IRC_BanList[II]:= Nicks[I]
else
begin
III:= Length(IRC_BanList);
SetLength(IRC_BanList, III + 1);
IRC_BanList[III]:= Nicks[I];
end;
end;
end;
SaveBanList;
LoadBanList;
for I:= 0 to High(ChannelList) do
SendData('PRIVMSG ' + ChannelList[I] + ' :' + Implode(', ', Nicks) + ' has been banned from using this bot.');
end;

procedure RemoveFromBanList(Nicks, ChannelList: TStringArray);
var
I, II: Integer;
B: TStringArray;
begin
SetLength(B, Length(Nicks));
for I:= 0 to High(Nicks) do
begin
II:= InStrArrEx(Nicks[I], IRC_BanList);
if(II >= 0) then
IRC_BanList[II]:= '';
end;
SaveBanList;
LoadBanList;
for I:= 0 to High(ChannelList) do
SendData('PRIVMSG ' + ChannelList[I] + ' :' + Implode(', ', Nicks) + ' has been unbanned from using this bot.');
end;

procedure Quit(M: String);
begin
SendData('QUIT: ' + M);
Quitting:= True;
end;

procedure ScriptTerminate;
begin
if(not(Quitting)) then
Quit('A Tootoot222 made IRC bot has been told to quit.');
if(not(TheConnection < 0)) then
FreeConnection(TheConnection);
end;

procedure JoinChannel(Chan: String);
begin
if(InStr(',', Chan)) then
begin
SendData('PRIVMSG ' + IRC_Static_JoinChan + ' :Joining this channel will cause me to part. I will not join this channel.');
Exit;
end;
if(InStr('#', Chan)) then
SendData('JOIN ' + Chan)
else
SendData('JOIN #' + Chan);
//TODO: make it return if it was able to join the channel or not
end;

function Banned(Nick: String): Boolean;
begin
Result:= InStrArr(Nick, IRC_BanList, False);
end;

function AbleToSend(Nick: String): Boolean;
begin
Result:= False;
if(Locked) then
begin
SendData('NOTICE ' + Nick + ' :' + Nick + ': The bot is locked. Please wait for the Master to unlock it.');
Exit;
end;
if(Banned(Nick)) then
begin
SendData('NOTICE ' + Nick + ' :' + Nick + ': You are banned from using this bot.');
Exit;
end;
Result:= True;
end;

procedure SetNick(NewNick: String);
begin
SendData('NICK ' + NewNick);
IRC_CurrentNick:= NewNick;
//TODO: make it return if it was able to set the nick or not
end;

procedure SetLock(NewLock: Boolean; Channels: TStringArray);
var
I: Integer;
begin
if(NewLock = Locked) then
Exit;
Locked:= NewLock;
for I:= 0 to High(Channels) do
if(NewLock) then
SendData('PRIVMSG ' + Channels[I] + ' :I am now locked. My Master must use the !unlock command to unlock me.')
else
SendData('PRIVMSG ' + Channels[I] + ' :I am now unlocked. My Master must use the !lock command to lock me.');
end;

var
Days, Months: TStringArray;

function DateTimeToString(T: TDateTime): String;
var
Y, Mo, D, H, Mi, S, MS: word;
begin
DecodeDate(T, Y, Mo, D);
DecodeTime(T, H, Mi, S, MS);
Result:= Days[DayOfWeek(T) - 1] + ' ' + IntToStr(D)
+ ' ' + Months[Mo - 1] + ' ' + IntToStr(Y) + ' ' +
IntToStr(H) + ':' + IntToStr(Mi) + ':' + IntToStr(S);
end;

function UnixTimeToStr(UnixTime: Int64): String;
begin
Result:= DateTimeToString(UnixToDateTime(UnixTime));
end;

function ReplaceBetween(S, LSearch, RSearch, ReplaceWith: String): String;
var
X, Y: Integer;
begin
X:= 0;
Y:= 0;
Result:= S;
repeat
if(Result = '') then
Exit;
X:= PosEx(LSearch, Result, X);
if(X < 1) then
Exit;
Y:= PosEx(RSearch, Result, X);
if(Y < 1) then
Exit;
Delete(Result, X, (Y - X) + 1);
Insert(ReplaceWith, Result, X);
X:= X + Length(ReplaceWith);
until(False);
end;

function WhichInStr(Arr: TStringArray; S: String): Integer;
begin
for Result:= High(Arr) downto 0 do
if(InStr(Arr[Result], S)) then
Exit;
end;

function ReadSRLManual: TStringArray;
var
ThePath: String;
X: Integer;
S: String;
begin
ThePath:= AppPath + 'Includes\SRL\SRL.html';
if(FileExists(ThePath)) then
begin
try
X:= OpenFile(ThePath, True);
if(not(X < 0)) then
begin
ReadFileString(X, S, FileSize(X));
Result:= Explode(#13#10, S);
end;
finally
CloseFile(X);
end;
end else
Writeln('Unable to locate ' + ThePath + '!');
end;

function ParaseSRLManual(Line: TStringArray; SearchFor: String): TMethod;
var
T, W, I: Integer;
CurrentFile: String;
SS: array of String;
GotInfo: Boolean;
begin
for I:= 0 to High(Line) do
begin
W:= WhichInStr(['srl\', 'by:', 'description:', Lowercase(SearchFor)], Lowercase(Line[I]));
if((W < 0) or (((W = 1) or (W = 2)) and (not(GotInfo)))) then
Continue;
Line[I]:= Trim(Replace(ReplaceBetween(Line[I], '<', '>', ''), '&nbsp;', ' '));
case W of
0: CurrentFile:= Trim(Line[I]);
1:
begin
if(GotInfo) then
Result.Creator:= Trim(TrimEx('By:', Line[I]));
end;
2:
begin
if(GotInfo) then
begin
SS:= Explode(' ', Trim(TrimEx('Description:', Line[I])));
for T:= 0 to High(SS) do
SS[T]:= Trim(SS[T]);
Result.Description:= Implode(#13#10, SS);
Exit;
end;
end;
3:
begin
W:= WhichInStr([' ' + Lowercase(SearchFor) + '(', ' ' + Lowercase(SearchFor) + ':', ' ' + Lowercase(SearchFor) + ';'], Lowercase(Line[I]));
if((W + 1) > 0) then
begin
Result.Declaration:= Line[I];
for T:= 0 to 4 do
Result.Declaration:= Replace(Line[I], ' ', ' ');
Result.FileIn:= CurrentFile;
GotInfo:= True;
end;
end;
end;
end;
Result.Declaration:= 'Unable to locate method "' + SearchFor + '" in SRL.html' + #13#10#0;
end;

function MethodToString(M: TMethod): String;
begin
with M do
begin
Result:= Declaration;
Result:= Result + #13#10 + 'Found in file: ' + FileIn;
Result:= Result + #13#10 + 'Made by: ' + Creator;
Result:= Result + #13#10 + 'Description: ' + Description;
end;
end;

function HandleNumberCommands(var CMessage: TMessage): Boolean;
var
Output: String;
begin
with CMessage do
begin
Result:= True;
Output:= '';
case Command of
'001': IRC_CurrentServer:= Host;
'005': //for now, i cbf to do anything with 005 params; i'm just going to output them (i'm also going to leave them in their own case, for when i decide to do things with them)
begin
Output:= TrimEx(IRC_CurrentNick + ' ', Param) + ' ' + TheMessage;
end;
'252', '254': Output:= TrimEx(IRC_CurrentNick + ' ', Param) + ' ' + TheMessage;
'433':
begin
OutputMessage(CMessage, 'Nickname "' + Param + '" is already in use.');
if(IRC_CurrentNick = IRC_Default_JoinNick1) then
SetNick(IRC_Default_JoinNick2)
else
SetNick(IRC_Default_JoinNick1);
JoinChannel(IRC_Static_JoinChan);
Result:= True;
Exit;
end;
'474':
begin
SendData('PRIVMSG ' + IRC_Static_JoinChan + ' :Unable to join channel ' + TrimEx(IRC_CurrentNick + ' ', Param) + ' because: ' + TheMessage);
JoinChannel(IRC_Static_JoinChan);
end;
end;
if(Output = '') then
Output:= TheMessage;
OutputMessage(CMessage, Output);
end;
end;

function HandleChatCommands(CMessage: TMessage): Boolean;
var
S, SS, SSS: String;
NoMess, B: Boolean;
begin
with CMessage do
begin
Result:= False;
if((Nick = #0) or (TheMessage = '')) then
Exit;
Result:= True;
if(Pos(#1, TheMessage) = 1) then
begin
SS:= TrimEx(#1, TheMessage) + ' ';
S:= Uppercase(NextToken(SS, ' '));
SS:= Trim(SS);
Result:= True;
case S of
'ACTION': OutputMessage(CMessage, Param + ': * ' + Nick + ' ' + SS);
'PING': SendData('NOTICE ' + Nick + ' :' + #1 + 'PING ' + SS + #1);
'TIME': SendData('NOTICE ' + Nick + ' :' + #1 + 'TIME ' + DateTimeToString(Now) + #1);
'VERSION': SendData('NOTICE ' + Nick + ' :' + #1 + 'VERSION IRC Bot made by Tootoot222 in SCAR. V3' + #1);
'FINGER': SendData('NOTICE ' + Nick + ' :' + #1 + 'FINGER What is this even for?' + #1);
else
Result:= False;
end;
if(Result) then
Exit;
end;
OutputMessage(CMessage, '');
if(not(StartsWith('!', TheMessage))) then
Exit;
S:= Copy(TheMessage, 1, Pos(';', TheMessage));
SS:= Trim(TrimEx(S, TheMessage));
S:= Trim(Lowercase(Replace(S, ';', ' ')));
if(High(S) > 0) then
if(not(S[1] = '!')) then
Exit;
NoMess:= False;
B:= False;
case S of
'!recover':
begin
if(StartsWith(IRC_Static_RecoverWord + ' ', SS)) then
begin
IRC_MasterNick:= TrimEx(IRC_Static_RecoverWord + ' ', SS);
RemoveFromBanList([IRC_MasterNick], [IRC_MasterNick]);
end;
end;
'!say':
begin
if(AbleToSend(Nick)) then
begin
if(StartsWith('#', Param)) then
SendData('PRIVMSG ' + Param + ' :' + SS)
else
if(Param = IRC_CurrentNick) then
SendData('PRIVMSG ' + Copy(SS, 1, Pos(' ', SS)) + ':' + TrimEx(Copy(SS, 1, Pos(' ', SS)), SS));
end else
B:= True;
end;
'!says':
begin
if(AbleToSend(Nick)) then
begin
if(StartsWith('#', Param)) then
SendData('PRIVMSG ' + Param + ' :' + Nick + ' says: ' + SS)
else
if(Param = IRC_CurrentNick) then
SendData('PRIVMSG ' + Copy(SS, 1, Pos(' ', SS)) + ':' + Nick + ' says: ' + TrimEx(Copy(SS, 1, Pos(' ', SS)), SS));
end else
B:= True;
end;
'!sayme':
begin
if(AbleToSend(Nick)) then
begin
if(StartsWith('#', Param)) then
SendData('PRIVMSG ' + Param + ' :' + #1 + 'ACTION ' + SS + #1)
else
if(Param = IRC_CurrentNick) then
SendData('PRIVMSG ' + Copy(SS, 1, Pos(' ', SS)) + ':' + #1 + 'ACTION ' + TrimEx(Copy(SS, 1, Pos(' ', SS)), SS) + #1);
end else
B:= True;
end;
'!send':
begin
if(AbleToSend(Nick)) then
begin
if(not(StartsWith('quit', Trim(Lowercase(SS))))) then
SendData(SS)
else
if(Nick = IRC_MasterNick) then
SendData(SS)
else
SendData('NOTICE ' + Nick + ' :You do not have permission to do this.');
end else
B:= True;
end;
'!banlist': SendData('NOTICE ' + Nick + ' :The users: ' + Implode(', ', IRC_BanList) + ' are banned.');
'!methodsearch':
begin
if(AbleToSend(Nick)) then
SendData('NOTICE ' + Nick + ' :' + Implode(#13#10 + 'NOTICE ' + Nick + ' :', Explode(#13#10, MethodToString(ParaseSRLManual(SRL_Lines, SS)))))
else
B:= True;
end;
else
begin
NoMess:= True;
if(not(Nick = IRC_MasterNick)) then
if(not(S = '')) then
SendData('NOTICE ' + Nick + ' : I am sorry ' + Nick + ', but I do not know the "' + S + '" commnad.');
end;
end;
if(not(Nick = IRC_MasterNick)) then
Exit;
if(B or Banned(Nick)) then
begin
if(NoMess) then
SendData('NOTICE ' + Nick + ' :You are banned ' + Nick + '. You may not use this bot.');
Exit;
end;
case S of
'!lock': SetLock(True, [IRC_Static_JoinChan]);
'!unlock': SetLock(False, [IRC_Static_JoinChan]);
'!kick': SendData('KICK ' + SS);
'!part': SendData('PART ' + SS);
'!join': JoinChannel(SS);
'!nick': SetNick(SS);
'!quit':
begin
if(not(Trim(SS) = '')) then
Quit(SS);
TerminateScript;
end;
'!prompt': SendData(Readln('Enter your message here:'));
'!master':
begin
if(not(Banned(Nick))) then
IRC_MasterNick:= TrimEx('master ', SS)
else
SendData('NOTICE ' + Nick + ' :' + TrimEx('master ', SS) + ' -- ' + SS + ' are banned from using this bot.');
end;
'!load banlist': LoadBanList;
'!save banlist': SaveBanList;
'!ban':
begin
SSS:= Copy(SS, 1, Pos(' ', SS));
AddToBanList(Explode('|', Lowercase(Trim(SSS))), Explode('|', TrimEx(SSS, SS)));
end;
'!unban':
begin
SSS:= Copy(SS, 1, Pos(' ', SS));
RemoveFromBanList(Explode('|', Lowercase(Trim(SSS))), Explode('|', TrimEx(SSS, SS)));
end;
'!mode':
begin
if(StartsWith('#', Param)) then
SendData('MODE ' + Param + ' ' + SS)
else
if(Param = IRC_CurrentNick) then
SendData('MODE ' + SS);
end;
else
if(not(S = '')) then
if(NoMess) then
SendData('NOTICE ' + Nick + ' :I am sorry ' + Nick + ', but I do not know the "' + S + '" commnad.');
end;
end;
end;

function HandleNormalCommands(CMessage: TMessage): Boolean;
var
P: Integer;
KickedChan, Kickee: String;
begin
with CMessage do
begin
Result:= True;
if(StartsWith('NOTICE AUTH', WholeLineData))then
begin
OutputMessage(CMessage, '-' + IRC_Static_Server + '- *** ' + TheMessage);
Exit;
end;
if(StartsWith('NOTICE', WholeLineData))then
begin
OutputMessage(CMessage, '-' + IRC_CurrentServer + '- ' + TheMessage);
Exit;
end;
case Command of
'KICK':
begin
P:= Pos('#', Param);
KickedChan:= Trim(Copy(Param, P, PosEx(' ', Param, P) - P));
Delete(Param, P, PosEx(' ', Param, P) - P);
Kickee:= Trim(Param);
if(Kickee = IRC_CurrentNick) then
begin
OutputMessage(CMessage, 'You were kicked from ' + KickedChan + ' by ' + Nick + ' (' + TheMessage + ')');
if(IRC_Static_AutoJoin) then
JoinChannel(KickedChan);
end else
OutputMessage(CMessage, Kickee + ' was kicked from ' + KickedChan + ' by ' + Nick + ' (' + TheMessage + ')');
end;
'MODE':
begin
if(Nick = #0) then
OutputMessage(CMessage, Host + ' sets mode: ' + TheMessage)
else
OutputMessage(CMessage, Nick + ' sets mode: ' + TheMessage);
end;
'NOTICE': OutputMessage(CMessage, '-' + Nick + '- ' + TheMessage);
'PRIVMSG': Result:= HandleChatCommands(CMessage);
'PART':
begin
if(not(TheMessage = '')) then
OutputMessage(CMessage, Nick + ' (' + User + '@' + Host + ') (' + TheMessage + ') has left ' + Param)
else
OutputMessage(CMessage, Nick + ' (' + User + '@' + Host + ') has left ' + Param);
end;
'JOIN': OutputMessage(CMessage, Nick + ' (' + User + '@' + Host + ') has joined ' + TheMessage);
'QUIT':
begin
if(not(TheMessage = '')) then
OutputMessage(CMessage, Nick + ' (' + User + '@' + Host + ') (' + TheMessage + ') has quit')
else
OutputMessage(CMessage, Nick + ' (' + User + '@' + Host + ') has quit');
end;
'NICK': OutputMessage(CMessage, Nick + ' is now known as ' + TheMessage);
else
Result:= False;
end;
end;
end;

procedure ParaseMessage(Data: String);
var
CMessage: TMessage;
DataArr: TStringArray;
NUH, Line: String;
I, L: Integer;
begin
DataArr:= Explode(CRLF, Data);
L:= High(DataArr);
for I:= 0 to L do
with CMessage do
begin
if(High(DataArr[I]) < 1) then
Continue;
WholeLineData:= DataArr[I];
if(StartsWith('PING', DataArr[I]))then
begin
Writeln(Timestamp + ' <- ' + DataArr[I]);
WholeLineData[2]:= 'O';
SendData(WholeLineData);
Continue;
end;
Line:= WholeLineData;
Sender:= NextToken(Line, ' ');
if(High(Sender) > 0) then
if(Sender[1] = ':')then
Delete(Sender, 1, 1);
NUH:= Sender;
Nick:= NextToken(NUH, '!');
User:= NextToken(NUH, '@');
Host:= NUH;
Command:= NextToken(Line, ' ');
if(InStr(' :', Line)) then
begin
Param:= NextToken(Line, ' :');
Line:= ':' + Line;
end else
Param:= NextToken(Line, ' :');
if(Param = #0) then
Param:= NextToken(Line, ' ');
Param:= TrimEx('* ', Param);
TheMessage:= Line;
NextToken(TheMessage, ':');
if(TheMessage = 'This nickname is registered. Please choose a different nickname, or identify via /msg NickServ identify <password>.') then
if(Nick = 'NickServ') then
SendData('PRIVMSG NickServ :identify ' + IRC_Static_NickServ);
if(IsNumber(Command)) then
if(HandleNumberCommands(CMessage)) then
Continue;
if(HandleNormalCommands(CMessage)) then
Continue;
Writeln(Timestamp + ' ' + Nick + ' - ' + User + ' - ' + Host + ' - ' + Command + ' - ' + Param + ' - ' + TheMessage);
Writeln(Timestamp + ' ' + DataArr[I]);
end;
end;


procedure MainLoop;
var
MessageBuffer: String;
begin
ClearDebug;
{$IFDEF Safe}
try
{$ENDIF}
SRL_Lines:= ReadSRLManual;
Quitting:= False;
Days:= ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
Months:= ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
Locked:= True;
LoadBanList;
IRC_MasterNick:= IRC_Default_MasterNick;
IRC_CurrentNick:= IRC_Default_JoinNick1;
ConnectToServer(IRC_Static_Server, IRC_Static_Port);
if(TheConnection < 0) then
Exit;
IRC_CurrentNick:= IRC_Default_JoinNick1;
SendData('USER ' + IRC_Static_Username + ' * * :' + IRC_Static_Realname);
SetNick(IRC_CurrentNick);
JoinChannel(IRC_Static_JoinChan);
repeat
MessageBuffer:= '';
if(TheConnection >= 0) then
ReadConnectionData(TheConnection, MessageBuffer);
if(not(MessageBuffer = '')) then
ParaseMessage(MessageBuffer);
until(False);
{$IFDEF Safe}
except
Writeln('ERROR!! The error was: ' + ExceptionToString(ExceptionType, ExceptionParam));
finally
end;
{$ENDIF}
end;

begin
MainLoop;
end.

Nava2

2009-02-08 12:30:11

Damn.

I need to clean mine up.

noidea

2009-02-08 13:10:18

unkown Identifer Implode
Line 205: [Error] (205:47): Unknown identifier 'Implode' in script C:\Program Files\SCAR 3.15b\Scripts\IRC SCAR.scar
;)

NiCbaZ

2009-02-08 14:48:17

From: noidea
unkown Identifer Implode
Line 205: [Error] (205:47): Unknown identifier 'Implode' in script C:\Program Files\SCAR 3.15b\Scripts\IRC SCAR.scar
;)


read?

(This requires SCAR 3.20 to run (or just add explode + implode yourself if you want 3.15)

Yakman

2009-02-08 16:41:23

good program, glad to see my client was being used for something :)

noidea

2009-02-08 17:18:28

From: NiCbaZ
read?


That wasnt there when I read the thread. I thimk you edited on purpose Tootoot!

Ron

2009-02-10 13:02:42

It would be cool if you put in the explode and implode functions so it would work on all scar versions rather than get everyone to install an unfinished, experimental version of scar.

I ran the program but I don't remember my username/password on freenode. I wish you commented the code, so I could follow how you did it. No one ever seems to comment.

Tootoot222

2009-02-13 11:53:22

@noidea: yea, i edited that in after you posted =p

@Ron: i added Explode + Implode, and i don't really comment, although i'm planning on rewriting the whole thing (now that i know how it all works i can probably make it a bunch better), and i'll probably comment that one (V4 will have a client UI, instead of using the debug box)

Freddy1990

2009-02-13 12:10:00

Lol, you wrote an IRC bot in SCAR? nice!

Ron

2009-02-13 12:39:33

@Toottoot, I look forward to your next version. :)

From: Freddy1990
Lol, you wrote an IRC bot in SCAR? nice!


You forgot RS Monkey's? His was pretty cool too.

Freddy1990

2009-02-13 12:41:03

From: Ron
@Toottoot, I look forward to your next version. :)



You forgot RS Monkey's? His was pretty cool too.


I thought he made a client?

Yakman

2009-02-13 12:46:27

a client is just a bot with a gui

and scar irc bots have been around for quite a long time, ever since the #srl irc channel started i believe.

Harry

2009-02-13 14:11:33

From: Yakman
a client is just a bot with a gui

and scar irc bots have been around for quite a long time, ever since the #srl irc channel started i believe.

Though no one likes any bots I make to go there…….they always ban them.

Tootoot, thanks, nice.

Kyle Undefined

2009-02-14 01:21:44

This makes me want to write one now :/

~Camo

Nava2

2009-02-14 12:39:38

program New;

const
Network = 'irc.freenode.net';
StartChan = '#srl';
StartNick = 'BobTheBuilder';

type
ChatMsg = Record
All, Msg, Com, Nick, Host, Chan: String;
end;
ChanOptions = Record
Chan : String;
BlockPubComs, BlackList : Boolean;
AccessList : TStringArray;
end;

var
Conn : Integer;
Chans : Array of ChanOptions;
BotNick : String;
AccessHosts : TStringArray;

// The Explode procedure looks through a string and separates it with whatever
// you suplied as a separator, and takes each value and puts them into an array.
// Example: Explode('*', 'a*b*c*d*e*');
// Made by Ron :)
function Explode(Separator, Str : string) : array of string;
var
i : integer;
begin
if(pos(Separator, Str) > 0)then
repeat
SetArrayLength(Result, i + 2);
Result[i] := copy(Str, 1, pos(Separator, Str)-1);
delete(Str, 1, pos(Result[i], Str)+Length(Result[i]));
Inc(i);
until(pos(Separator, Str) = 0)
else
SetArrayLength(Result, 1);
Result[i] := Str;
end;

//Narcle
function StrInArr(str : string; arrS : TStringArray) : Boolean;

var
I, L, H : Integer;

begin
Result := True;
Str := LowerCase(Str);
L := Low(arrS); H := High(arrS);
for I := L to H do
if Pos(Str, LowerCase(arrS[I])) > 0 then
Exit;
Result := False;
end;

{*******************************************************************************
procedure RemoveElement(Index : Integer; var Arr : Array);
By: MylesMadness
Description: Removed Piece Index of an Array, the Array is defined by the user.
*******************************************************************************}
Procedure RemoveElement(Index : Integer; var Arr : TStringArray);

var
I, H : Integer;

begin
H := High(Arr);
for I := Index to H do
Arr[Index] := Arr[Index + 1];
SetArrayLength(Arr, High(Arr));
end;

function Col(Num : Integer):String;

begin
Result := '' + IntToStr(Num) + ' ';
end;

function Bold(s : String) : String;
begin
Result := '' + s + '';
end;

function Enter : String;
begin
Result := #13 + #10;
end;

function Caps(S : String) : String;
begin
Result := Capitalize(LowerCase(S));
end;

procedure SendData(Text : String);
begin
SendConnectionData(Conn, Text + #13 #10);
Writeln('->> ' + Text);
end;

procedure PrivMsg(Target, Msg : String);
begin
SendData('PRIVMSG ' + Target + ' :' + Msg);
end;

procedure Notice(Target, Msg : String);
begin
SendData('NOTICE ' + Target + ' :' + Msg);
end;

function GetParams(S : String) : TStringArray;

begin
Result := Explode(' ', S);
end;

procedure NoticeAllChans(S : String);

var
I : Integer;

begin
for I := 0 to High(Chans) do
Notice(Chans[I].Chan, S);
end;

procedure MsgAllChans(S : String);

var
I : Integer;

begin
for I := 0 to High(Chans) do
PrivMsg(Chans[I].Chan, S);
end;

function HSGet(C: ChatMsg; Username, Skill: string; Options : TStringArray) : TStringArray;

var
I, II, III, L : Integer;
S : String;
arrS : TStringArray;
arrarrS : Array of TStringArray;

begin
Result := ['N/A', 'N/A', 'N/A']
try
S := GetPage('http://hiscore.runescape.com/index_lite.ws?player=' + Replace(UserName, ' ', '_'))
except
Exit;
end;
arrS := Explode(#10, S);

SetArrayLength(arrarrS, 29);
for I := 0 to 28 do
arrarrS[I] := Explode(',', ArrS[I]);
case LowerCase(Skill) of
'overall' : I := 0;
'attack', 'att' : I := 1;
'defence', 'def' : I := 2;
'strength', 'str' : I := 3;
'hitpoints', 'hp' : I := 4;
'ranged', 'range' : I := 5;
'prayer', 'pray' : I := 6;
'magic', 'mage' : I := 7;
'cooking', 'cook' : I := 8;
'woodcutting', 'wc' : I := 9;
'fletching', 'fletch' : I := 10;
'fishing', 'fish' : I := 11;
'firemaking', 'fm' : I := 12;
'crafting', 'craft' : I := 13;
'smithing', 'smith' : I := 14;
'mining', 'mine' : I := 15;
'herblore', 'herb', 'herby' : I := 16;
'agility' : I := 17;
'thieving', 'thief' : I := 18;
'slayer' : I := 19;
'farming', 'farm' : I := 20;
'runecraft', 'rc', 'runecrafting' : I := 21;
'hunter' : I := 22;
'construction', 'con': I := 23;
'summoning' : I := 24;

'duel_tournament' : I := 25;
'bounty_hunters', 'bh' : I := 26;
'bounty_hunters_rougue', 'bhr' : I := 27;
'fist_of_guthix', 'fog' : I := 28;
else
Exit;
end;

for III := 0 to High(Options) do
begin
case LowerCase(Options[III]) of
'rank' : II := 0;
'level', 'lvl', 'score' : II := 1;
'xp' : II := 2;
else II := -1;
end;
if II <> -1 then
begin
L := Length(Result);
SetArrayLength(Result, L + 1);
Result[L] := arrarrS[I][II];
if Result[L] = '-1' then
Result[L] := 'N/A';
end;
end;
end;

function BlackCheck(Channel : String) : Boolean;

var
I : Integer;

begin
for I := 0 to High(Chans) do
if LowerCase(Channel) = LowerCase(Chans[I].Chan) then
begin
Result := Chans[I].Blacklist;
Break;
end;
end;

procedure SetBlackList(Channel : String; OnOff : Boolean);

var
I : Integer;

begin
for I := 0 to High(Chans) do
if LowerCase(Channel) = LowerCase(Chans[I].Chan) then
begin
Chans[I].Blacklist := OnOff;
Break;
end;
end;

function PubComCheck(Channel : String) : Boolean;

var
I : Integer;

begin
for I := 0 to High(Chans) do
if LowerCase(Channel) = LowerCase(Chans[I].Chan) then
begin
Result := Chans[I].BlockPubComs;
Break;
end;
end;


procedure SetBlockPubComs(Channel : String; OnOff : Boolean);

var
I : Integer;

begin
for I := 0 to High(Chans) do
if LowerCase(Channel) = LowerCase(Chans[I].Chan) then
begin
Chans[I].BlockPubComs := OnOff;
Break;
end;
end;

procedure ModAccess(C : ChatMsg; Nick : String; AddDel : Boolean);
var
I, II : Integer;
S : String;
begin
for I := 0 to High(Chans) do
if LowerCase(C.Chan) = LowerCase(Chans[I].Chan) then
Break;
if AddDel then
begin
SetArrayLength(Chans[I].AccessList, Length(Chans[I].AccessList) + 1);
Chans[I].AccessList[High(Chans[I].AccessList)] := Nick;
SendData('WHOIS ' + Nick);
ReadConnectionData(Conn, S);
end else
begin
for II := 0 to High(Chans[I].AccessList) do
if LowerCase(Nick) = LowerCase(Chans[I].AccessList[II]) then
Break;
RemoveElement(II, Chans[I].AccessList);
end;
end;

function CheckAccess(C : ChatMsg) : Boolean;

var
I, II : Integer;

begin
for I := 0 to High(Chans) do
if LowerCase(Chans[I].Chan) = LowerCase(C.Chan) then
for II := 0 to High(Chans[I].AccessList) do
if LowerCase(C.Nick) = LowerCase(Chans[I].AccessList[II]) then
begin
Result := True;
Exit;
end;
end;

function SetOptions(C : ChatMsg) : String;

var
S : String;

begin
if not CheckAccess(C) then Result := '';
C.Msg := LowerCase(C.Msg);
S := Copy(C.Msg, PosEx(' ', C.Msg, Pos(' ', C.Msg) + 1), Length(C.Msg));
case Between(' ', ' ', C.Msg) of
'b-public' : SetBlockPubComs(C.Chan, S = 'off');
'b-channel' : SetBlackList(C.Chan, S = 'off');
'access': ModAccess(C, Between(' ', ' ', S), Copy(S, LastPos(' ', S), Length(S)) = 'remove');
end;
Result := C.Nick + ' sets ' + Between(' ', ' ', C.Msg) + ' to ' + S + '.';
end;

function CheckHost(Host : String) : boolean;

begin
Result := StrInArr(Copy(Host, Pos('@', Host) + 1, Length(Host)), AccessHosts);
end;

procedure AddHost(Host : String);

var
L : Integer;

begin
L := Length(AccessHosts);
SetArrayLength(AccessHosts, L + 1);
AccessHosts[L] := Host;
end;

procedure RemoveHost(Host : String);

var
I : Integer;

begin
for I := 0 to High(AccessHosts) do
if Host = AccessHosts[I] then
begin
Swap(AccessHosts[I], AccessHosts[High(AccessHosts)]);
SetArrayLength(AccessHosts, High(AccessHosts));
Exit;
end;
end;

procedure TextCommands(C : ChatMsg);

var
Target, S : String;
arrS, arrS2 : TStringArray;
I : Integer;

begin
if (Pos('!', C.Msg) = 1) or (PubComCheck(C.Chan) and (Pos('@', C.Msg) = 1)) then
Target := C.Nick
else
if (Pos('@', C.Msg) = 1) then
Target := C.Chan
else
Exit;
S := LowerCase(Copy(C.Msg, 2, Pos(' ', C.Msg) - 1));
if Length(S) <= 1 then
S := LowerCase(Copy(C.Msg, 2, Length(S)));
case S of
'say ' : S := Copy(C.Msg, Pos(' ', C.Msg) + 1, Length(C.Msg));
'g-msg ' : if CheckHost(C.Host) then
MsgAllChans(Copy(C.Msg, Pos('g-msg ', LowerCase(C.msg)) + 6, Length(C.Msg)))
else
S := Col(12) + 'Sorry, not high-enough bot access.';
'g-not ' : if CheckHost(C.Host) then
NoticeAllChans(Copy(C.Msg, Pos('g-not ', LowerCase(C.msg)) + 6, Length(C.Msg)))
else
S := Col(12) + 'Sorry, not high-enough bot access.';
'add-host ' : if CheckHost(C.Host) then
AddHost(Copy(C.Msg, Pos('add-host', LowerCase(C.msg)) + 10, Length(C.Msg)));
'remove-host ' : if CheckHost(C.Host) then
RemoveHost(Copy(C.Msg, Pos('remove-host', LowerCase(C.msg)) + 12, Length(C.Msg)));
'set ' : S := SetOptions(C);
'whois ': begin end;
'part ', 'gtfo ' :
begin
arrS := GetParams(C.Msg);
S := 'Asked to leave by: ' + C.Nick;
try
S := S + ' Reason: ' + Copy(C.Msg, Pos(' ', C.Msg) + 1, Length(C.Msg));
except
end;
SendData('PART ' + C.Chan + ' ' + S);
Target := C.Chan;
for I := 0 to High(Chans) do
if Chans[I].chan = C.Chan then
begin
Swap(Chans[I], Chans[High(Chans)]);
SetArrayLength(Chans, High(Chans));
Break;
end;
end;
'skill ' :
begin
arrS := GetParams(C.Msg);
writeln('Skill : ' + arrs[1]);
S := Copy(C.Msg, Pos(arrS[1], C.Msg) + Length(arrS[1]) + 1, Length(C.Msg));
Writeln('Username: ' + S);
try
arrS2 := HSGet(C, S, arrS[1], ['rank', 'lvl', 'xp']);
for I := 0 to 2 do
writeln(arrS2[i]);
S := Col(12) + 'Player: ' + Col(5) + Bold(Caps(S)) + Col(5) + Col(12) + ' Skill: ' + Col(8) + Caps(arrS[1]) + Col(12) +' Ranked: ' +
Col(8) + arrS2[0] + Col(12) + ' Level: ' + Col(8) + arrS2[1] + Col(12) +' XP: ' +
Col(8) + arrS2[2] + Col(12);
except
S := Col(12) + 'Invalid Skill [' + Bold(Col(8) + arrS[1] + Col(12)) + '] -- Inputted by: ' + Col(5) + C.Nick + Col(12) + ' -- Correct Syntax: ' +
Col(8) + '!skill ' + Col(4) + Bold('[skill] [username]');
end;
end;
'setnick ' :
begin
arrS := GetParams(C.Msg);
if CheckHost(C.Host) then
begin
SendData('NICK ' + arrS[1]);
MsgAllChans(Col(12) + C.Nick + ' has just set ' + BotNick + '''s name to ' + arrS[1] + ' sorry for any confusion.');
BotNick := arrS[1];
Exit;
end else
S := Col(12) + 'Sorry, not high-enough bot access.';
end;
'terminate ':
begin
if CheckHost(C.Host) then
begin
Writeln('Terminated: ' + C.Msg);
TerminateScript;
end else
S := Col(12) + 'Sorry, not high-enough bot access.';
end;
else
begin
S := Copy(C.Msg, 0, Pos(' ', C.Msg) - 1);
if S = '' then
S := C.Msg;
S := Col(12) + '- Invalid Command [' + Bold(Col(8) + S + Col(12)) + '] -- Inputted by: ' + Col(5) + C.Nick;
end;
end;
if Target = C.Chan then
PrivMsg(Target, S)
else
Notice(Target, S);
end;

procedure JoinChannel(Channel : String);

var
L : Integer;

begin
L := Length(Chans);
SetArrayLength(Chans, L + 1);
Chans[L].Chan := Channel;
Chans[L].AccessList := ['navatwo'];
SendData('JOIN ' + Channel);
end;

//Credits to mixster for help with the explodes
procedure Interpret;

var
I : Integer;
S : String;
arrS : TStringArray;
C : ChatMsg;

begin
ReadConnectionData(Conn, S);
arrS := Explode(':', Between(':', #13 + #10, S));
SetArrayLength(arrS, 2);

C.All := ArrS[0];
C.Msg := ArrS[1];
C.Com := Between(' ', ' ', arrS[0]);
C.Nick := Copy(arrS[0], 1, Pos('!', arrS[0]) - 1);
C.Host := Between('!', ' ', arrS[0]);
C.Chan := Between(' ', ' ', Copy(arrS[0], Pos(' ', arrS[0]) + 1, Length(arrS[0])));

if Pos('Connection Timed Out', C.Msg) <> 0 then
SendData('QUIT');

if S = '' then Exit;

Writeln('Full: ' + S);
Writeln('All: ' + C.All);
Writeln('Msg: ' + C.Msg);
Writeln('Com: ' + C.com);
Writeln('Nick: ' + C.Nick);
Writeln('Host: ' + C.Host);
Writeln('Chan: ' + C.Chan);
Writeln(' ');

case C.Com of
'PRIVMSG' : if (Pos('!', C.Msg) = 1) or (Pos('@', C.Msg) = 1) then TextCommands(C);
'INVITE' : if not BlackCheck(C.Chan) then
begin
JoinChannel(C.Msg);
PrivMsg(C.Msg, Col(8) + C.Nick + Col(12) + 'invited me into this channel! If you would like me to LEAVE use the command: ' + Col(5)
+ '!part <Reason>.');
end else
Notice(C.Nick, 'Channel: ' + C.Msg + ' has been blacklisted, please ask someone with access to remove it.');
'433' : begin
SendData('NICK NBot');
JoinChannel('#NBot');
end;
end;
end;

procedure StartNetwork(Host : String; Port, TimeOut : Integer);

begin
Conn := OpenConnection(Host, Port, TimeOut);
SendData('USER ' + StartNick + ' * * :' + 'NBot');
SendData('NICK ' + StartNick);
SendData('PASS asdfasdfasdfsdf');
BotNick := StartNick;
end;

procedure ScriptTerminate;

begin
SendData('QUIT :I''m leaving!');
end;

var s : String;

begin
StartNetwork(Network, 6667, 15000);
Wait(1000);
ReadConnectionData(Conn, S);
JoinChannel(StartChan);
writeln(s);
AccessHosts := [];
try
repeat
Interpret;
Wait(10);
until false;
except
end;
SendData('PRIVMSG #Nava2 : FML');
end.

Eh, mine ain't special.