Включаешь компьютер, запускаешь мирку (mIRC), пытаешься зайти на канал... опа: address is banned. С трудом вспоминаешь количество бутылок выпитого тобой накануне пива и лестные выражения в адрес операторов канала - картина начинает проясняться... 

"Ну ничего", - думаешь ты, - "создам свой канал, приглашу друзей. сам буду банить, кикать и раздавать привилегии.

Только чем привлечь посетителей? Чтобы канал из "сборища трех калек" превратился в интересное посещаемое место? В голову приходит мысль: "Нужно посадить на канал бота." Однако ничего кроме "автопривета" в mIRC ты не писал, а как развлекать посетителей канала еще не придумал...

Не парься,  сегодня я расскажу тебе, как написать mIRC-бота канала #anekdot.

Поскольку не каждый посетитель канала заходит только для того, чтобы почитать анекдоты, дадим mIRC-боту возможность записи анекдота в базу прямо с канала с запоминанием даты и ника рассказавшего его, а также выдачи списка анекдотов за конкретную дату.

Кроме того, наш бот просто обязан выделяться на фоне остальных безликих серых eggdrop-ботов. Главное, не переборщи с цветами и интерактивностью. Итак, приступим...

База анекдотов

Для удобства, базу анекдотов будем хранить в папке "anekdot" корневого каталога мирки в виде текстовых фалов, так как стандартными средствами mIRC ни с какой известной базой работать мы не сможем. База будет состоять из следующих файлов:

  • kick.txt - набор фраз для команды /kick;
  • noflood.txt - фразы в ответ на сообщение "Не флуди!";
  • list.txt - список тем;
  • data.txt - данные об авторах анекдотов;
  • other.txt - анекдоты темы "остальные".

Давай рассмотрим каждый файл подробнее...

kick.txt

Анекдоты можно будет показывать на канале в нескольких режимах, в том числе по команде !anek (как у большинства остальных ботов).
Уверен, найдутся такие члены IRC-чата, которые от избытка энергии в голове будут посылать команду !anek чаще, чем бот будет выдавать на канал очередной анекдот. Будем кикать их с канала с сообщением  вроде "Может хватит клаву трахать?". Список подходящих к случаю сообщений мы построчно разместим в файле kick.txt.

noflood.txt

В этом файле, аналогично предыдущему, расположим построчно фразы, которые наш mIRC-бот будет произносить вместе с киком в ответ на сообщение "Не флуди!".

list.txt

Этот файл будет состоять из трех частей, разделенных пробелами:

[тема] [количество] [- описание]

Без него работа бота невозможна, так как при попытке записи анекдота в базу по команде !tell [тема] бот сперва будет сверяться со списком возможных тем, затем брать количество анекдотов по теме и, увеличив на единицу, присваивать его в качестве номера записываемого анекдота, одновременно переписывая данные файла list.txt. Поэтому, для начала добавим в файл list.txt одну строку:

other 0 разное

data.txt

В него будет автоматически записываться информация об авторе анекдота:

[имя канала] [тема] [номер] [ник рассказавшего] [адрес] [дата] [время]

разделенные пробелами. Думаю, любому человеку будет приятно, если бот напишет, что этот анекдот рассказан им такого-то числа.

other.txt

В принципе, этот файл создастся автоматически сразу после записи в базу первого анекдота по теме other. Но тебе полезно знать его структуру. Вдруг, ты захочешь заполнить базу вручную (изменив соответствующим образом файлы list.txt, data.txt и [тема].txt).

Каждой теме соответствует отдельный файл под названием [тема].txt (без квадратных скобок). Первая строка пустая, далее следуют пары "номер анекдота и  текст", разделенные пустой строкой. Заканчивается файл двумя пустыми строками. Например:

(Пустая строка)
¤1¤
Анекдот 1.
(Пустая строка)
¤2¤
Анекдот 2.
(Пустая строка)
(Пустая строка)

Предвижу твой вопрос: "Можно ли размещать текст анекдота в нескольких строках?". Можно.

Кодим mIRC-бота

Код нашего бота будем хранить в корневом каталоге mIRC в файле anekdot.txt.

При выборе ника я обратился к Lingvo, который дал мне слово "humo(u)rist". Так как использование круглых скобок в названии ника запрещено, называем бота humo[u]rist и запускаем mIRC. Переходим в окно написания скриптов, создаем новый файл командой File / New и сохраняем его под именем anekdot.txt.

Простые события

Добавляем первые строки кода, которые выполнятся сразу после соединения с IRC-сервером, заставляя бота идентифицировать себя и зайти на канал #anekdot.

on 1:CONNECT: {
/msg NickServ IDENTIFY [пароль]
/join #anekdot
}

Возможна ситуация, когда наш бот будет расположен на удаленном сервере, и мы сможем только править файл anekdot.txt, доступный на ftp-сервере. Для этого добавим код, который означает, что сразу после старта (on START), независимо от того, изменился ли anekdot.txt, бот будет перегружать его каждую минуту, а каждые 5 минут на канал будет выдаваться новый анекдот.

on 1:START: {
/timer4 -m 0 60000 /reload -rs anekdot.txt
/timer2 -m 0 300000 /anek_rest
}

Для тех, кто продолжительное время находится на канале, безразлично, пятый или сто десятый анекдот рассказывает бот. Но тем, кто зашел на канал совсем недавно, хочется наблюдать непустое окно, поэтому обработаем событие "on JOIN" входа на канал #anekdot посетителя. За выдержку паузы между анекдотами в 5 секунд будет отвечать переменная %tmr2:

on 1:JOIN:#: {
  if ( $chan == #AnEkDoT ) {
    if ( %tmr2 != on ) /anek #anekdot
    /mode $chan  +v $nick
  }
  /set %tmr2 off
}

Обработка текста на канале

Посетители могут отправлять на канал #anekdot любой текст. Необходимо анализировать его, и соответствующим образом реагировать на команды !anek, !help, !date, !tell, !end, !list. Сделать это можно, используя код on 1:TEXT:*:#AnEkDoT:{...}.

Чтобы выяснить, является ли текст командой (начинается с восклицательного знака), будем использовать проверку по условию ($left($1,1) == !). Как было сказано, интервал между анекдотами не может быть меньше 5 секунд, об окончании его свидетельствует значение off для переменной %tmr2. Если это условие выполнено, то производится анализ составных частей команды. На нарушение условия или логики команды бот отреагирует сообщением. Иначе, на канал будет отправлен анекдот. Код, который будет выполняться в ответ на команду !anek, смотри во врезке. По команде !help будем отправлять на канал подготовленный текст помощи (алиас help), а на команду !date нужно выдать список анекдотов, добавленных за конкретную дату (алиас anek_date). Для выдачи на канал списка тем по команде !list используется алиас list_s.

Любой человек, находящийся на канале, может добавить в базу свой анекдот, дав боту команду !tell с указанием темы из списка доступных. Запись будет начинаться процедурой с алиасом listen_to_anek (смотри врезку), и выключаться автоматически через три минуты, либо досрочно по команде !end. Если посетитель послал команду окончания записи, хотя никто не включал ее, можно уточнить, сколько пива он выпил. :-) Бот будет записывать в файл все слова человека с определенным ником, запуская алиас wr_anek, если для этого выполнено несколько условий, главным из которых является равенство переменной %listen значению on.

Мы ведь предлагаем услуги высшего качества, поэтому если команда боту незнакома, нужно сообщить об этом на канале.

on 1:TEXT:*:#AnEkDoT:{
  if ( $left($1,1) == ! ) {
    ;На слово !anek
    if (( $1 == !anek ) || ( $1 == !анек )) {
      ;Небольшая защита от особо настырных
      if ( %kick_nik == $nick ) {
        if ( %num_anek > 10 ) /kick_nick
        else /inc %num_anek
      }
      else {
        /set %kick_nik $nick
        /set %num_anek 1    
      }
      ;Через 10 секунд начинаем подсчет сначала
      /timer12 -m 0 10000 /unset_kick
      ;--
      if ( $2 == $null ) {
        if ( %tmr2 == on ) /msg $chan 4Попробуй еще раз, 12 $+ $nick $+ 4, я пока поищу анекдот4...
        else /anek #anekdot
      }
      else {
        if ( $2 isnum ) && ( $3 == $null ) /msg $chan 4Для выбора номера анекдота мне нужна тема,12 $nick $+ 4 ! 3( см. 4!help 3)
        else if ( $gettok( $read( anekdot/list.txt, w, * $+ $2 $+ *),1,32) != $2 ) /msg $chan 4Нет такой темы,12 $nick $+ 4 ! 3( см. 4!help 10=> 4!list 3)
        else {
          if ( $3 != $null ) && (( $3 <= 0 ) || ( $3 > $gettok( $read( anekdot/list.txt, w, * $+ $2 $+ *),2,32) )) /msg $chan 4Где ты такой номер нашел,12 $nick $+ 4 ? 3( см. 4!list 3)
          else {
            /set %file_read $2
            if ( $3 isnum ) /set %n_an $3
            else /set %n_an off
            if ( %tmr2 == on ) /msg $chan 4Попробуй еще раз, 12 $+ $nick $+ 4, я пока поищу анекдот4...
            else /anek #anekdot
          }
        }
      }
    }
    ;На слово !help
    elseif (( $1 == !help ) || ( $1 == !помощь )) && ( $2 == $null ) {
      if ( $chan == #AnEkDoT) /help
    }
    ;На слово !date
    elseif (( $1 == !date ) || ( $1 == !дата )) && ( $3 == $null ) {
      if ( $chan == #AnEkDoT) /anek_date $chan $2
    }
    ;На слово !tell Возможность предложить свой анекдот
    elseif (( $1 == !tell ) || ( $1 == !рассказать )) && ( $chan == #AnEkDoT ) {
      if ( $nick == $null ) /msg $chan 12 $nick $+ 4, тебе отказано в записи...
      else {
        if ( $2 == $null ) /msg $chan 12 $nick $+ 4, укажи пожалуйста тему. 3( см. 4!list 3)
        else {
          /set %file_write $2
          if ( $gettok( $read( anekdot/list.txt, w, * $+ $2 $+ *),1,32) == $2 ) {
            if ( %listen != on ) /listen_to_anek
            elseif ( $nick != %nik ) /msg $chan 4Погоди еще немного,12 $nick $+ 4, пусть12 %nik 4рассказывает 4...
          }
          else //msg $chan 4Нет такой отдельной темы,12 $nick $+ 4. 3( см. 4!help 10=> 4!list 3)
        }
      }
    }
    ;На слово !end
    elseif (( $1 == !end ) || ( $1 == !конец )) && ( $chan == #AnEkDoT ) {
      if ( %listen == on ) && ( $nick == %nik ) /stop_listen
      else /msg $chan 4И что ты хочешь этим сказать,12 $nick $+ 4? 4:)
    }
    ;На слово !list список тем
    elseif (( $1 == !list ) || ( $1 == !список )) && ( $2 == $null ) && ( $chan == #AnEkDoT) {
      if ( %tmr_list != on ) {
        /set %tmr_list on
        /list_s
      }
      else /msg $chan 4А одного раза тебе мало,12 $nick $+ 4? 4:)
    }
    ;На слово !top10 и !top-10
    elseif (( $1 == !top-10 ) || ( $1 == !топ-10 )) && ( $3 == $null ) && ( $chan == #AnEkDoT ) {
      if ( $2 != $null ) && ( $gettok( $read( anekdot/list.txt, w, * $+ $2 $+ *),1,32) != $2 ) /msg $chan 4Нет такой темы,12 $nick $+ 4 ! 3( см. 4!help 10=> 4!list 3)
      else /top $chr(40) $chan $2
    }
    elseif (( $1 == !top10 ) || ( $1 == !топ10 )) && ( $3 == $null ) && ( $chan == #AnEkDoT ) {
      if ( $2 != $null ) && ( $gettok( $read( anekdot/list.txt, w, * $+ $2 $+ *),1,32) != $2 ) /msg $chan 4Нет такой темы,12 $nick $+ 4 ! 3( см. 4!help 10=> 4!list 3)
      else /top $chr(41) $chan $2
    }
    else /msg $chan 4Что-то не знаю такой команды,12 $nick $+ 4. 3( см. 4!help 3) 4:)
  }
  ;считаю кол-во улыбок
  if ( $chr(40) isin $1- ) && ( $chan == #AnEkDoT ) && ( $1 != !top ) && ( $address( $nick,2) != *!*@dcfto-k7.krsk.mps ) /top_anek $chan $chr(40) $pos( $1- , $chr(40),0) $nick
  if ( $chr(41) isin $1- ) && ( $chan == #AnEkDoT ) && ( $1 != !top ) && ( $address( $nick,2) != *!*@dcfto-k7.krsk.mps ) /top_anek $chan $chr(41) $pos( $1- , $chr(41),0) $nick
  ;---- Этот цикл должен крутиться всегда для записи анекдота в файл, но записывать только в случае совпадения всех параметров
  if ( $1 != !утв ) && ( $1 != $null ) && ( $1 != !top10 ) && ( $1 != !топ10 ) && ( $1 != !top-10 ) && ( $1 != !топ-10 ) && ( $1 != !help ) && ( $1 != !помощь ) && ( $1 != !tell ) && ( $1 != !рассказать ) && ( $1 != !list ) && ( $1 != !список ) && ( $1 != !end ) && ( $1 != !конец ) && ( %listen == on ) && ( $nick == %nik ) && ( $chan == #AnEkDoT ) /wr_anek $1-
}

Обработка текста в привате

on 1:TEXT:!*:?: {
  if ( $address( $nick,2) == *!*@www.ecolora.com ) || ( $address( $nick,2) == *!*@10.94.109.12 ) {
    if ( $1 ==  !clear_tmr2 ) {
      /set %tmr2 off
      /msg $nick 12Обнулил переменную tmr2... :)
    }
    ;На слово !anek
    if (( $1 == !anek ) || ( $1 == !анек )) {
      if ( $2 == $null ) {
        if ( %tmr2 == on ) /msg $chan 4Попробуй еще раз, 12 $+ $nick $+ 4, я пока поищу анекдот4...
        else /anek #anekdot
      }
      else {
        if ( $2 isnum ) && ( $3 == $null ) /msg $chan 4Для выбора номера анекдота мне нужна тема,12 $nick $+ 4 ! 3( см. 4!help 3)
        else if ( $gettok( $read( anekdot/list.txt, w, * $+ $2 $+ *),1,32) != $2 ) /msg $chan 4Нет такой темы,12 $nick $+ 4 ! 3( см. 4!help 10=> 4!list 3)
        else {
          if ( $3 != $null ) && (( $3 <= 0 ) || ( $3 > $gettok( $read( anekdot/list.txt, w, * $+ $2 $+ *),2,32) )) /msg $chan 4Где ты такой номер нашел,12 $nick $+ 4 ? 3( см. 4!list 3)
          else {
            /set %file_read $2
            if ( $3 isnum ) /set %n_an $3
            else /set %n_an off
            if ( %tmr2 == on ) /msg $chan 4Попробуй еще раз, 12 $+ $nick $+ 4, я пока поищу анекдот4...
            else {            
              if ( $4 != $null ) {
                /anek $4
                /msg $nick 12Отправил анекдот по адресу $4 $+... :)
              }
              else /anek
            }
          }
        }
      }
    }
  }
}

Выдача анекдота на канал

За выдачу анекдота в канал отвечает алиас anek. Чтобы информировать бота о начале отправки анекдота на канал, нужно "поднять флаг", то есть присвоить переменной %tmr2 значение on. Через 5 секунд можно менять это значение на off. Заданные тема и номер анекдота хранятся в переменных %file_read и %n_an, соответственно. Номер каждого анекдота заключен в символы с кодом 164. Телом анекдота под определенным номером считаем текст между строкой "символ-номер-символ" и пустой строкой. Если номер не задан, то бот попробует считать случайный анекдот из файла с произвольной темой, используя функцию $rand(). Если общая длина двух считываемых строк не превышает 250 символов, они будут склеены для экономии места. Авторство и дата записи анекдота считываются из файла data.txt.

;--Скрипт выдает анекдоты
alias anek {
  ;Присваиваю значение на .. секунд чтобы поменьше флуда на канале было(см.таймер)
  /set %tmr2 on
  /timer1 -m 1 5000 /set %tmr2 off ;Запускаем таймер
  ;Общее количество строк в файле
  /set %l $lines(anekdot/ $+ %file_read $+ .txt)
  ;Так как последние две пустые
  /dec %l
  /dec %l
  ;ВАРИАНТ 1:номер задан
  if ( %n_an isnum ) {
    /set %text $read(anekdot/ $+ %file_read $+ .txt, w, * $+ $chr(164) $+ %n_an $+ $chr(164) $+ *)
    /set %cur $readn
    /inc %cur
    /set %text $read(anekdot/ $+ %file_read $+ .txt, l, %cur)
  }
  ;ВАРИАНТ 2:номер не задан
  else {
    ;Начальная инициализация1
    /set %text 0
    ;Ищем пустую строку, ведь за ней следующий анекдот
    while ( %text != $null ) {
      /set %cur $rand(1, %l)
      ;Случайная строка из всех строк в файле
      /set %text $read(anekdot/ $+ %file_read $+ .txt, l, %cur)
      ;Начальная инициализация (берем след. строку.)
    }
    /inc %cur
    /set %text $read(anekdot/ $+ %file_read $+ .txt, l, %cur)
    ;Все равно номер анекдота определяем, чтобы знать по нему и по теме кто его рассказал
    if ( %text != $null ) {
      /set %n_an $gettok( %text, 1, 164)
      /inc %cur
      /set %text $read(anekdot/ $+ %file_read $+ .txt, l, %cur)
    }
  }
  ;КОНЕЦ ОБРАБОТКИ ВАРИАНТОВ
  ;Если за пустой строкой опять пустая строка или ошибка
  if ( %text == $null ) /set %frase 4Этот анекдот - матершинный, не могу такое рассказывать. :-)
  else {
    if ( $1 == $null ) /msg $1 12Тема4 %file_read $+ 12. Номер 4¤ $+ %n_an $+ ¤12:
    else /msg $1 12Тема4 %file_read $+ 12. Номер 4¤ $+ %n_an $+ ¤12:
  }
  ;Запомнили первую строчку после номера
  /set %frase 3
  ;ВЫДАЕМ ПРИКОЛ
  while ( %text != $null ) {
    ;Если фраза длинная, то выдаем ее на канал частями
    if ( $len( %frase) > 250 ) {
      if ( $1 == $null ) /amsg $1 3 %frase $+ ...
      else /msg $1 3 %frase $+ ...
      /set %frase 3
    }
    /set %frase $addtok( %frase, %text, 32)
    /inc %cur
    /set %text $read(anekdot/ $+ %file_read $+ .txt, l, %cur)
  }
  if ( $1 == $null ) /amsg $1 3 %frase
  else /msg $1 3 %frase
  if ( $1 == $null ) /amsg $1 4 $+ $gettok( $read(anekdot/data.txt, w, *#AnEkDoT %file_read %n_an $+ *),4,32) 12 $gettok( $read(anekdot/data.txt, w, *#AnEkDoT %file_read %n_an $+ *),6,32)
  else /msg $1 4 $+ $gettok( $read(anekdot/data.txt, w, * $+ %file_read %n_an $+ *),4,32) 12 $gettok( $read(anekdot/data.txt, w, *#AnEkDoT %file_read %n_an $+ *),6,32)
  /unset %frase
  ;Теперь настырность оценивается заново
  /unset_kick
  ;Запоминаю тему, и номер для топа
  /set %top_theme %file_read
  /set %top_nom %n_an
  ;Сбрасываю номер анека
  /set %n_an off
  ;Следующая тема берется почти наугад :))
  if ( %file_read == other ) /set %file_read $gettok( $read(anekdot/list.txt, l, $rand(1, $lines(anekdot/list.txt))),1,32)
  else /set %file_read other
  /timer2 -m 0 300000 /anek_rest
}
;-

;-Данный алиас отвечает за выдачу анекдотов в режиме покоя
alias anek_rest {
  if ( %tmr2 != on ) /anek #anekdot
}
;--Небольшая защита от особо настырных пишущих !anek
alias kick_nick {
  /KICK #AnEkDoT %kick_nik $read(anekdot/kick.txt, l, $rand(1, $lines(anekdot/kick.txt)))
  /unset_kick
}

alias unset_kick {
  /unset %kick_nik
  /unset %num_anek
}

;--Алиас для записи улыбок в текст ($1-канал, $2-вид улыбки, $3-кол-во улыбок, $4-ник)
alias top_anek {
  /var %top_tn = %top_theme %top_nom
  if ( $gettok( $read(anekdot/data.txt, w, *#AnEkDoT %top_tn $+ *),5,32) == $address( $4,2) ) /msg $1 12Умный,4 $4 $+ 12? Сам себе рейтинг повышаешь? 4:))
  elseif ( $3 > 20 ) /msg $1 12Не многовато ли улыбок,4 $4 $+ 12? 4:))
  else {
    /var %vrem = $read( anekdot/top.txt, w, * %top_tn *)
    /var %n $readn
    if ( %n != $null ) && ( %n != 0 ) {
      /var %col = $gettok( %vrem,5,32) + $3
      /write -dl $+ %n anekdot/top.txt
      /write anekdot/top.txt $1 %top_tn $2 %col $4 $address( $4,2) $asctime(hh:nn:ss)
    }
    else /write anekdot/top.txt $1 %top_tn $2 $3 $4 $address( $4,2) $asctime(hh:nn:ss)
  }
}

Запись анекдота на канале

Если посетитель дал боту команду !tell (смирррно! :-)), то последний должен выполнить необходимую инициализацию и включить запись, проинформировав рассказчика анекдота. Начало записи показано во врезке под алиасом listen_to_anek (смотри врезку). Сперва нужно запомнить ник автора, далее получить количество анекдотов по данной теме и инкрементировать его (то есть увеличить на единицу). Когда все вычисления произведены, в конец файла указанной темы добавляется строка с номером вида ¤%nom1¤, где %nom1 - переменная с номером анекдота.

;--Данные алиасы отвечают за запись анекдота в файл
alias listen_to_anek {
  /set %nik $nick
  ;читаем всю строку из лист по данной теме
  /set %wrd $read( anekdot/list.txt, w, * $+ %file_write $+ *)
  ;запоминаем номер этой строки
  /set %n_line3 $readn
  ;выбираем второе слово и инкременируем его
  /set %nom1 $gettok( %wrd,2,32)
  /inc %nom1
  ;выбираем оставшиеся части
  /set %part1 $gettok( %wrd,1,32)
  /set %part2 $gettok( %wrd,3-,32)
  ;удаляя и вставляя строку из list.txt осуществляю ее репласе
  /write -dl %n_line3 anekdot/list.txt
  /write -il %n_line3 anekdot/list.txt %part1 %nom1 %part2
  ;а дальше уже запись анекдота
  /write anekdot/ $+ %file_write $+ .txt $chr(164) $+ %nom1 $+ $chr(164)
  /msg $chan 11,1Тема:4,1 %file_write $+ 11,1. Слушаю,4,1 %nik $+ 11,1. У тебя4,1 3 минуты11,1:
  /set %listen on
  ;Запоминаю тему, и номер для топа
  /set %top_theme %file_write
  /set %top_nom %nom1
  /timer5 -m 1 180000 /clear_listen_nik
  /timer2 -m 0 300000 /anek_rest
}

Для постоянной записи на канале всего сказанного человеком, давшим боту команду !tell до момента принудительной или автоматической остановки записи используется алиас wr_anek. Чтобы исключить внедрение исполняемого кода в текст анекдота, используем проверку строки на символ "|" с кодом 124.

;Алиас для постоянной записи сказанного на канале, если ее возможность включена
alias wr_anek {
/set %fr743 $1-
/set %fr743 $replace( %fr743, $chr(124),хрен те)
/write anekdot/ $+ %file_write $+ .txt %fr743
/unset %fr743
}
 

Если время записи истекло или посетитель канала дал команду !end (вольно, салага :-)) для ее принудительной остановки, необходимо запомнить авторство. Для начала нужно сообщить автору, что запись остановлена, а также занести данные в файл data.txt. Это сделает процедура под алиасом clear_listen_nick. В нескольких строках заключены нехитрые махинации с файлом темы анекдота, позволяющие добавить в его конец 2 пустые строки. Думаю, ты сам догадаешься, зачем это нужно.

;Конец записи анекдота
alias clear_listen_nik {
  /msg #AnEkDoT 11,1Прикол записан под номером4,1 %nom1 $+ 11,1,4,1 %nik $+ 11,1. 4,1:))))
  /set %listen off  ;Выключаю возможность записи анекдота
  if ( $address( %nik,2) == *!*@www.ecolora.com ) || ( %nik == EcoloRa ) /set %nik humo[u]rist
  /write anekdot/data.txt #AnEkDoT %file_write %nom1 %nik $address( %nik,2) $date $asctime(hh:nn:ss)
  ;Все это для формирования пустой строки нужно
  /write anekdot/ $+ %file_write $+ .txt ***
  /set %lll $lines(anekdot/ $+ %file_write $+ .txt)
  /write -il %lll anekdot/ $+ %file_write $+ .txt $null
  /set %lll $lines(anekdot/ $+ %file_write $+ .txt)
  /write -dl %lll anekdot/ $+ %file_write $+ .txt
  ;------------
  /timer2 -m 0 300000 /anek_rest
  ;Даю возможность всем насладиться анекдотом
  /amsg 4В базу записан новый анекдот!!!
  /set %file_read %file_write
  /set %n_an %nom1
  /anek
  /amsg 4Все пожелания автор принимает в привате и на каналах!!!
}
;--

Для досрочной остановки записи анекдота существует процедура с алиасом stop_listen. Вызывается она по команде !end, своим кодом дублируя часть процедуры с алиасом clear_listen_nik.

alias stop_listen {
  /timer5 -m 1 0 /clear_listen_nik
}

Темы, помощь и !date

Осталось реализовать выдачу на канал списка тем, помощи и списка анекдотов за указанную дату. Сейчас я попытаюсь описать краткий алгоритм каждой процедуры.

Код процедуры, которая выдает темы после команды !list, отправленной на канал, разместим под алиасом list_s. Здесь важно исключить эксплуатацию бота нецивилизованными посетителями и присвоить на 30 секунд переменной %tmr_list значение on. Информация по темам берется из файла list.txt, куда мы с тобой ее до этого занесли. Файл обрабатывается построчно, поэтому проверь, чтобы в нем не было лишних строк.

;--Данный алиас отвечает за выдачу списка тем на канале
alias list_s {
  ;Второй раз подряд лист не выдаем в течение 30 секунд.
  /set %tmr_list on
  /timer6 -m 1 30000 /unset %tmr_list
  ;---
  /msg $chan 4Список отдельных тем:
  /set %n_list 1
  /set %text_list $read(anekdot/list.txt, l, %n_list)
  if ( %text_list == $null ) /msg $chan 4Список тем отсутствует.
  while ( %text_list != $null ) {
    /msg $chan 12 $gettok( %text_list,1,32) 10[ $+ $gettok( %text_list,2,32) $+ ]3 $gettok( %text_list,3-,32)
    /inc %n_list
    /set %text_list $read(anekdot/list.txt, l, %n_list)
  }
}

Код, обрабатывающий команду !help состоит из строк, начинающихся с /msg $chan. Они заставят бота отправить на канал вспомогательную информацию, которую мы сами занесли в него.

alias help {
  /msg $chan 2Важное примечание: 3В 4( ) 3другой вариант команды; 3В 4[] 3необязательный параметр.
  /msg $chan 4!anek (!анек) [тема] [номер]3 - послушать [по теме] [за номером];
  /msg $chan 4!list (!список)3 - список отдельных тем;
  /msg $chan 4!top10 (!топ10) [тема] 3 - 10 лучших [по теме];
  /msg $chan 4!top-110 (!топ-10) [тема] 3 - 10 худших [по теме];
  /msg $chan 4!date (!дата) [**/**/****] 3 - список анекдотов за указанную дату;
  /msg $chan 4!tell (!рассказать) тема3 - записать свой анекдот (дается 3 минуты);
  /msg $chan 4!end (!конец)3 - досрочно прекратить запись анекдота;
  /msg $chan 4!help (!помощь)3 - помощь.
}

Выдача списка анекдотов за конкретную дату расположена в процедуре anek_date. На время ее работы анекдоты на канал выдаваться не будут, поскольку переменной %tmr2 присваивается значение on. Если дата не указана во втором слове команды, то берем текущее значение функции $date, иначе дату нужно проверить и сообщить обо всех выявленных нарушениях формата: "Чо за год?", "А месяц де?", - и прочих. Если face-control пройден, то бот обработает построчно файл data.txt и выдаст список всех анекдотов, добавленных в базу за указанную дату.

;Выдача списка анекдотов за конкретную дату
;Передаю сюда канал -$1, дату - $2(не обязательно)
alias anek_date {
  ;Присваиваю значение на .. секунд чтобы поменьше флуда на канале было(см.таймер)
  /set %tmr2 on
  /timer1 -m 1 5000 /set %tmr2 off
  ;Если дата не передана, то беру за сегодня
  if ( $2 == $null ) /var %date_date = $date
  else /var %date_date = $2
  ;После присвоения надо проверить
  if ( $mid(%date_date,1,2) isnum ) && ( $mid(%date_date,4,2) isnum ) && ( $mid(%date_date,7,4) isnum ) {
    if ( $mid(%date_date,1,2) < 01 ) || ( $mid(%date_date,1,2) > 31 ) /msg $1 4Это какой-такой день?
    elseif ( $mid(%date_date,4,2) < 01 ) || ( $mid(%date_date,4,2) > 12 ) /msg $1  4Это какой-такой месяц?
    elseif ( $mid(%date_date,7,4) < 2002 ) || ( $mid(%date_date,7,4) > 2005 ) /msg $1 4Это какой-такой год?
    elseif ( $mid( %date_date,3,1) != $chr(47) ) || ( $mid( %date_date,6,1) != $chr(47) ) /msg $1 4А где разделитель в виде "/"?
    else {
      /msg $1 4Список анекдотов за 12 $+ %date_date
      /var %date_str = $read(anekdot/data.txt, w, * $+ $2 $+ *)
      if ( $readn == 0 ) /msg $1 Отсутствует!
      else {     
        /var %l = $lines(anekdot/data.txt)
        /var %i = $readn
        /var %j = 1
        while ( %i <= %l ) {
          /var %date_str = $read(anekdot/data.txt, l, %i)
          if ( $gettok( %date_str,6,32) == %date_date ) {
            /msg $1 2 %j 12Тема и номер4: $gettok( %date_str,2-4,32)
            /inc %j
          }
          /inc %i
        }
        /msg $1 3Ну и хватит... :)
      }
    }
  }
  else /msg $1 4Сдается, мне, что ты проверяешь мое терпение. :)
}

В поддержку mIRC и всего русского :-)

Возможно, ты считаешь, что лучше взять xIRC-компоненты для Delphi и сваять код, так как это проще и быстрее работает... А когда нужно будет внести изменения в код, ты будешь переписывать, компилировать и выкладывать файл на сервер, останавливая и запуская бота? Я же просто изменю код и выложу его на сервер. mIRC послушно скушает новые команды, без остановки бота. Так что... mIRC форева! :-)

На этом все. Бери mIRC (для которой написан код, можешь портировать его под другую версию самостоятельно), пиши, пробуй, экспериментируй. Застолби место самого популярного канала и его автора в вашей IRC-сети. :-) Удачи...

  1. Для перехода в окно написания скриптов нужно активировать в mIRC пункт меню Tools / Scripts Editor... или Tools / Remote Scripts...(для ранних версий)
  2. Чтобы никто не воспользовался нашим ником в дальнейшем, нужно его зарегистрировать, отправив NickServ-у сообщение REGISTER [пароль] [e-mail]
  3. Для получения абсолютных прав на канале #anekdot, его нужно зарегистрировать, послав ChanServ-у команду REGISTER #anekdot [пароль] [описание канала]
  4. mIRC-скрипты можно писать в любом текстовом файле с произвольным расширением (чаще *.mrc или *.txt) либо в ini-файле.
  5. Чаще алиасы пишутся в отдельном файле, загружаемом в mIRC в категорию алиасов. Однако их можно напрямую включать в код скриптов помечая словом alias.
  6. Функция $readn позволяет получить номер строки файла, которая участвовала в последней функции $read().
  7. Этот и другие скрипты для mIRC ты можешь найти на сайте по адресу http://irc.ecolora.com/?lng=ru в разделе Новичок.

Add comment


Security code
Refresh