Advertisement
f4gug

rea

Nov 13th, 2017
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TCL 38.65 KB | None | 0 0
  1.  ###############################################################################
  2. #
  3. # Reanimator
  4. # v1.2 (27/03/2016)   ©2013-2016 Menz Agitat
  5. #
  6. # IRC: irc.epiknet.org  #boulets / #eggdrop
  7. #
  8. # Mes scripts sont téléchargeables sur http://www.eggdrop.fr
  9. #
  10.  ###############################################################################
  11.  
  12. #
  13. # Description
  14. #
  15. # Reanimator permet à votre Eggdrop d'intervenir lorsque personne ne parle
  16. # pendant un certain temps sur un chan. Vous pourrez par exemple lui faire
  17. # raconter des blagues ou s'apitoyer sur sa condition de bot.
  18. #
  19. # Les interventions peuvent afficher une ou plusieurs lignes de texte, envoyer
  20. # des commandes RAW au serveur, ou même exécuter des commandes tcl. Votre bot
  21. # devient ainsi virtuellement capable de dire ou faire tout ce que vous pourrez
  22. # imaginer afin de redonner vie à votre chan.
  23. # De plus, un certain nombre de variables spéciales sont reconnues (détaillées
  24. # plus bas dans la section configuration).
  25. #
  26. # Pour plus de réalisme, le bot simule le temps de frappe des lignes de texte
  27. # et les affiche après un certain délai qui varie selon leur longueur.
  28. #
  29. # La commande !reanimator_test permet au propriétaire de l'eggdrop de tester
  30. # en direct l'effet de l'intervention spécifiée.
  31. # Syntaxe : !reanimator_test {{ligne 1}[ {ligne 2}[ {...}]]}
  32. #
  33. # La commande !reanimator_stats permet au propriétaire de l'eggdrop de compter
  34. # et d'afficher le nombre d'interventions dans la base de données, ainsi que
  35. # quelques autres informations concernant les réglages du script.
  36. #
  37. # Pour activer Reanimator sur un chan, vous devez taper ceci en partyline de
  38. # l'Eggdrop :
  39. # .chanset #NomDuChan +reanimator
  40. # et ceci pour le désactiver :
  41. # .chanset #NomDuChan -reanimator
  42. #
  43.  ###############################################################################
  44.  
  45. #
  46. # Changelog
  47. #
  48. # 1.0
  49. #       - 1ère version
  50. # 1.1
  51. #       - Correction : les caractères spéciaux dans le nom du chan, le nick de
  52. #           l'eggdrop ou le nick d'un utilisateur ne devraient plus poser de problème
  53. #           avec les variables %lastnick% %chan% et %botnick%.
  54. #       - Ajout de 2 nouvelles variables : %tcl_randnick% et %tcl_randnick<index>%
  55. #           à utiliser à la place des variables %randnick% et %randnick<index>% dans
  56. #           les interventions de type /tcl. Les caractères spéciaux sont neutralisés
  57. #           dans les nicks qu'elles retournent (voir documentation incluse dans le
  58. #           script).
  59. # 1.11
  60. #       - Correction : les variables spéciales %randnick% %tcl_randnick%
  61. #           %randnick<index>% et %tcl_randnick<index>% ne fonctionnaient pas
  62. #           correctement.
  63. # 1.12
  64. #       - Correction : le fonctionnement des variables %randnick% et %tcl_randnick%
  65. #           ainsi que celui de %randnick<index>% et %tcl_randnick<index>% avaient été
  66. #           inversés, par conséquent les caractères spéciaux étaient neutralisés quand
  67. #           ils n'auraient pas dû l'être et inversement.
  68. # 1.13
  69. #       - Correction : remplacement des [clock seconds] par [unixtime] dans le code,
  70. #           car pour une raison que j'ignore la fonction clock seconds retourne
  71. #           parfois une heure erronée.
  72. # 1.14
  73. #       - Correction : les variables spéciales %randnick%, %randnick<index>%,
  74. #           %tcl_randnick% et %tcl_randnick<index>% ne fonctionnaient pas correctement
  75. #           avec les nicks contenant des accolades.
  76. #       - Quelques optimisations du code.
  77. # 1.2
  78. #       - Les interventions ne seront désormais plus répétées tant que toutes les
  79. #           autres n'auront pas été vues une fois.
  80. #
  81.  ###############################################################################
  82.  
  83. #
  84. # Licence
  85. #
  86. #       Cette création est mise à disposition selon le Contrat
  87. #       Attribution-NonCommercial-ShareAlike 3.0 Unported disponible en ligne
  88. #       http://creativecommons.org/licenses/by-nc-sa/3.0/ ou par courrier postal à
  89. #       Creative Commons, 171 Second Street, Suite 300, San Francisco, California
  90. #       94105, USA.
  91. #       Vous pouvez également consulter la version française ici :
  92. #       http://creativecommons.org/licenses/by-nc-sa/3.0/deed.fr
  93. #
  94.  ###############################################################################
  95.  
  96. if {[::tcl::info::commands ::reanimator::uninstall] eq "::reanimator::uninstall"} { ::reanimator::uninstall }
  97. if { [join [split [::tcl::string::range [lindex $version 0] 0 5] "."] ""] < 1620 } { putloglev o * "\00304\002\[Reanimator - Erreur\]\002\003 La version de votre Eggdrop est \00304\002$version\002\003; Reanimator ne fonctionnera correctement que sur les Eggdrops version 1.6.20 ou supérieure." ; return }
  98. if { [info tclversion] < 8.5 } { putloglev o * "\00304\002\[Reanimator - Erreur\]\002\003 Reanimator nécessite que Tcl 8.5 (ou plus) soit installé pour fonctionner. Votre version actuelle de Tcl est \00304\002$tcl_version\002\003." ; return }
  99. package require Tcl 8.5
  100. namespace eval reanimator {
  101.  
  102.  
  103.  
  104.  ###############################################################################
  105. ### Configuration
  106.  ###############################################################################
  107.  
  108.     ### Après combien de temps (en minutes) sans que personne ne parle, le bot
  109.     # interviendra-t-il ?
  110.     variable revive_after 1
  111.  
  112.     ### Intervalle de temps minimum entre deux interventions du bot si personne ne
  113.     # parle (en minutes)
  114.     variable revive_again_after 2
  115.  
  116.     ### Nicks/handles que Reanimator doit ignorer (si vous possédez par exemple un
  117.     # autre bot susceptible de parler de temps à autres, et que vous ne voulez pas
  118.     # que cela soit considéré comme une preuve d'activité par Reanimator, ajoutez
  119.     # son nick ou son handle)
  120.     variable ignores {}
  121.  
  122.     ### Nicks/handles que Reanimator ne doit jamais utiliser en choisissant un
  123.     # nick aléatoirement pour les variables %randnick% ou %randnick<index>%
  124.     variable randnick_exclusion_list {}
  125.  
  126.     ### Vitesse à laquelle le bot écrit (pour simuler le temps de frappe)
  127.     # reply_speed_coeff = coefficient de rapidité, multiplie/divise la rapidité
  128.     # (0.5 divise par 2 la vitesse de référence, etc)
  129.     # reply_speed_offset = ajoute ou enlève des secondes au délai (pour l'affinage)
  130.     variable reply_speed_coeff 1
  131.     variable reply_speed_offset 5
  132.  
  133.     ### Mode monochrome : filtre les codes de couleur/gras/... dans tout ce qui
  134.     # est affiché par Reanimator sur un chan. (0 = désactivé ; 1 = activé)
  135.     # Remarque : le mode monochrome s'active automatiquement sur les chans où
  136.     # le mode +c est mis.
  137.     variable monochrome 0
  138.  
  139.     ### Base de données des interventions possibles pour ranimer un chan.
  140.     # Chaque intervention d'une seule ligne doit se présenter sous cette forme :
  141.     #   {{intervention}}.
  142.     # Les interventions sur plusieurs lignes sont possibles de cette façon :
  143.     #   {{1ère ligne} {2ème ligne} {...}}.
  144.     # Vous pouvez utiliser des codes couleurs/gras/... selon la syntaxe habituelle
  145.     #   d'un Eggdrop.
  146.     # Vous pouvez utiliser un certain nombre de variables spéciales dans les
  147.     # interventions.
  148.     # Certaines d'entre-elles existent en deux versions dont l'une est préfixée
  149.     # par tcl_; celle-ci doit être utilisée dans les interventions de type /tcl
  150.     # (voir plus bas) car les caractères spéciaux y sont neutralisés.
  151.     #       %botnick%
  152.     #           Sera remplacé par le nick actuel de l'Eggdrop.
  153.     #       %chan%
  154.     #           Sera remplacé par le nom du chan.
  155.     #       %hour%
  156.     #           Sera remplacé par l'heure qu'il est (seulement l'heure).
  157.     #       %hour_short%
  158.     #           Sera remplacé par l'heure qu'il est (seulement l'heure et sans le 0 au
  159.     #           début).
  160.     #       %minutes%
  161.     #           Sera remplacé par l'heure qu'il est (seulement les minutes).
  162.     #       %minutes_short%
  163.     #           Sera remplacé par l'heure qu'il est (seulement les minutes et sans le 0
  164.     #           au début).
  165.     #       %seconds%
  166.     #           Sera remplacé par l'heure qu'il est (seulement les secondes).
  167.     #       %seconds_short%
  168.     #           Sera remplacé par l'heure qu'il est (seulement les secondes et sans le 0
  169.     #           au début).
  170.     #       %day_num%
  171.     #           Sera remplacé par le jour numérique.
  172.     #       %day%
  173.     #           Sera remplacé par le jour de la semaine en toutes lettres.
  174.     #       %month_num%
  175.     #           Sera remplacé par le mois numérique.
  176.     #       %month%
  177.     #           Sera remplacé par le mois en toutes lettres.
  178.     #       %year%
  179.     #           Sera remplacé par l'année.
  180.     #       %idle_time%
  181.     #           Sera remplacé par le temps écoulé depuis que personne n'a parlé.
  182.     #           Si personne n'a jamais parlé sur ce chan et qu'une intervention
  183.     #           contient %idle_time%, elle sera ignorée et une autre intervention
  184.     #           sera choisie aléatoirement.
  185.     #       %lastnick%
  186.     #           Sera remplacé par le nick de la dernière personne ayant parlé sur ce
  187.     #           chan. Si personne n'a jamais parlé sur ce chan ou si la dernière
  188.     #           personne ayant parlé n'est plus sur le chan et qu'une intervention
  189.     #           contient %lastnick%, elle sera ignorée et une autre intervention
  190.     #           sera choisie aléatoirement.
  191.     #           Les changements de nick de la dernière personne ayant parlé sont
  192.     #           surveillés et %lastnick% est tenu à jour automatiquement.
  193.     #       %randnick% / %tcl_randnick%
  194.     #           Sera remplacé par un nick choisi aléatoirement parmi les utilisateurs
  195.     #           présents, à l'exception de l'Eggdrop.
  196.     #           Si vous utilisez 3 fois la variable %randnick% dans une même
  197.     #           intervention, elle sera remplacée par 3 nicks différents.
  198.     #   %randnick<index>% / %tcl_randnick<index>%
  199.     #           Sera remplacé par un nick pris aléatoirement sur le chan.
  200.     #           Si vous utilisez 3 fois la variable %randnick<index>% dans une même
  201.     #           réponse, elle sera remplacée par 3 fois le même nick si l'index est
  202.     #           identique. L'index est une valeur numérique arbitraire.
  203.     #           Voici un exemple qui vous permettra de mieux comprendre :
  204.     #           {{%randnick1% tu es là ?} {%randnick1% ?} {%randnick2% n'est pas là non plus je suppose ?}}
  205.     #           donnera sur 3 lignes différentes : Pierre tu es là ? | Pierre ? | Jean n'est pas là non plus je suppose ?
  206.     # Certaines commandes sont reconnues dans les interventions :
  207.     #       /me <texte>
  208.     #           Fait faire un CTCP ACTION au bot
  209.     #       /putserv <commande RAW à envoyer au serveur>
  210.     #           Permet d'envoyer des commandes au serveur IRC.
  211.     #           Exemple : {/putserv kick #monchan Machin raison du kick}
  212.     #           Pour plus d'informations, consultez http://www.faqs.org/rfcs/rfc1459.html
  213.     #       /tcl <commande(s)>
  214.     #           Permet d'exécuter une ou plusieurs commandes tcl. Vous pouvez par
  215.     #           exemple appeler une proc d'un autre script.
  216.     #           Exemple : {/tcl putquick "PRIVMSG #testchan :test [regsub -all {\W} "a-b-c $::botnick" "|"]"}
  217.     # Veuillez noter que si vous souhaitez utiliser les caractères } et { dans les
  218.     # messages standards, les /me et les /putserv, vous devrez les neutraliser
  219.     # comme ceci : \} et \{.
  220.     # Par contre, vous ne devez pas neutraliser les { et } lorsque vous utilisez
  221.     # /tcl, vous devez juste veiller à ce qu'ils soient équilibrés.
  222.     #
  223.     # Astuce : vous pouvez inclure des lignes vides dans une intervention afin
  224.     # d'ajouter un délai supplémentaire entre deux lignes d'une même intervention.
  225.     # Pour cela, vous devez régler reply_speed_offset à 1 (ou plus) et ajouter
  226.     # autant de {} que vous souhaitez de secondes supplémentaires de délai.
  227.     #       Exemple : {{/me baille} {} {} {} {} {} {/me s'ennuie}}
  228.     # Dans cet exemple, nous avons ajouté 5 secondes de délai supplémentaire entre
  229.     # l'affichage de /me baille et de /me s'ennuie. Notez que les lignes vides
  230.     # ainsi ajoutées ne seront pas affichées.
  231.     #      
  232.     variable database {
  233.  
  234.         {{/me baille test} {} {} {} {} {} {/me s'ennuie}}
  235.  
  236.         {{/me s'ennuie test } {} {} {} {} {} {} {} {} {} {} {/me baille}}
  237.  
  238.     }
  239.  
  240.     ### Voici quelques exemples d'interventions utilisant /putserv ou /tcl afin
  241.     ### d'en illustrer les possibilités :
  242.     # Le bot tape !randquote pour afficher une citation aléatoire (nécessite le
  243.     # script Public Quotes System) :
  244.     #       {{!randquote} {/tcl ::pubqsys::randquote - - - %chan% ""}}
  245.     # Le bot tape !vdm pour afficher une VDM aléatoire (nécessite le script VDM) :
  246.     #       {{!vdm} {/tcl ::vdm::vdm_command - - - %chan% ""}}
  247.     # Le bot tape !dtc pour afficher une citation aléatoire de www.danstonchat.com
  248.     # (nécessite le script DansTonChat) :
  249.     #       {{!dtc} {/tcl ::dtc::command - - - %chan% ""}}
  250.     # Le bot invoque quelque chose pour ranimer le chan (nécessite le script The
  251.     # Summoner) :
  252.     #       {{!invoque pour ranimer le chan} {/tcl ::summoner::main %botnick% - - %chan% "pour ranimer le chan"}}
  253.     # Le bot construit un scénario entre deux nicks aléatoires (nécessite le
  254.     # script IRC Story) :
  255.     #       {{!story %randnick1% %randnick2%} {/tcl ::IRCSTORY::pub_disp_story %botnick% - - %chan% "%tcl_randnick1% %tcl_randnick2%"}}
  256.     # Le bot demande à l'Oracle s'il est bien le bot le plus intelligent du chan,
  257.     # et l'Oracle lui répond (nécessite le script Oracle) :
  258.     #       {{!oracle suis-je le bot le plus intelligent du chan ?} {/tcl ::Oracle::ask_oracle %botnick% - - %chan% "suis-je le bot le plus intelligent du chan ?"} {omg qui a parlé ? oO}}
  259.     # Le bot se voice (s'il possède un accès suffisant sur le chan) :
  260.     #       {{/putserv MODE %chan% +v %botnick%}}
  261.     # Autre exemple d'utilisation de /tcl :
  262.     #       {{/tcl puthelp "PRIVMSG %chan% :test [regsub -all {\W} "a-b-c $::botnick" "|"]"}}
  263.  
  264.  ###############################################################################
  265. ### Fin de la configuration
  266.  ###############################################################################
  267.  
  268.  
  269.  
  270.      #############################################################################
  271.     ### Initialisation
  272.      #############################################################################
  273.   variable scriptname "Reanimator"
  274.   variable version "1.2.20160327"
  275.     setudef flag reanimator
  276.     # DEBUGMODE peut valoir 0 (désactivé), 1 (pas d'avertissement pour chaque
  277.     # activité détectée) ou 2 (tout)
  278.     variable DEBUGMODE 0
  279.     variable delayed_talk_running 0
  280.     variable random_indexes {}
  281.     variable revive_after [expr {$revive_after * 60}]
  282.     variable revive_again_after [expr {$revive_again_after * 60}]
  283.     array set ::reanimator::memory {}
  284.     # Procédure de désinstallation (le script se désinstalle totalement avant chaque rehash ou à chaque relecture au moyen de la commande "source" ou autre)
  285.     proc uninstall {args} {
  286.         putlog "Désallocation des ressources de \002[set ::reanimator::scriptname]\002..."
  287.         foreach binding [lsearch -inline -all -regexp [binds *[set ns [::tcl::string::range [namespace current] 2 end]]*] " \{?(::)?$ns"] {
  288.             unbind [lindex $binding 0] [lindex $binding 1] [lindex $binding 2] [lindex $binding 4]
  289.         }
  290.         namespace delete ::reanimator
  291.     }
  292. }
  293.  
  294.  ##############################################################################
  295. ### Réanimation d'un chan
  296.  ##############################################################################
  297. proc ::reanimator::defibrillator {chan} {
  298.     set counter 1
  299.     set text "!misfit!"
  300.     if {
  301.         (![::tcl::dict::exists $::reanimator::random_indexes $chan])
  302.         || ([::tcl::dict::get $::reanimator::random_indexes $chan] eq {})
  303.     } then {
  304.         ::reanimator::build_random_indexes $chan
  305.     }
  306.     # On sélectionne l'intervention.
  307.     while { [set text [::reanimator::substitute_special_vars_1st_pass $chan $text]] eq "!misfit!" } {
  308.         set text [lindex $::reanimator::database [lindex [::tcl::dict::get $::reanimator::random_indexes $chan] 0]]
  309.         ::tcl::dict::set ::reanimator::random_indexes $chan [lreplace [::tcl::dict::get $::reanimator::random_indexes $chan] 0 0]
  310.         incr counter
  311.         # La ligne suivante sert à protéger contre un infinite loop dans le cas où
  312.         # la base de données ne contient que des interventions comportant des
  313.         # variables nécessitant qu'une personne ait déjà parlé sur le chan, et que
  314.         # ce n'est pas le cas.
  315.         if { $counter > 1000 } {
  316.             putloglev o * [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - avertissement\]\003 La base de données ne contient aucune intervention utilisable sur $chan pour le moment. L'intervention est annulée."]
  317.             return
  318.         }
  319.     }
  320.     foreach line $text {
  321.         regexp {^([^\s]+)\s} $line {} first_word
  322.         # hormis pour la commande /tcl, on neutralise les caractères qui choquent
  323.         # Tcl, à l'exception des codes de couleur/gras/...
  324.         if { (![::tcl::info::exists first_word]) || ($first_word ne "/tcl") } {
  325.             regsub -all {\\\\([\}\{])} [regsub -all {(?!\\002|\\003|\\022|\\037|\\026|\\017)[\$[\[\]"\\]} $line {\\&}] {\1} line ; # "
  326.         }
  327.         # Filtrage des codes couleur/gras/... si le mode monochrome est activé ou
  328.         # si le flag +c est détecté sur le chan.
  329.         # Remarque : stripcodes ne fonctionne pas du fait que les \ ont été
  330.         # neutralisés
  331.         if { ($::reanimator::monochrome) || ([::tcl::string::match *c* [lindex [split [getchanmode $chan]] 0]]) } {
  332.              regsub -all {\\003[0-9]{0,2}(,[0-9]{0,2})?|\\017|\\037|\\002|\\026|\\006|\\007} $line "" line
  333.         }
  334.         lappend ::reanimator::talk_queue [list $chan $line]
  335.     }
  336.     if { !$::reanimator::delayed_talk_running } { ::reanimator::delayed_talk }
  337. }
  338.  
  339.  ##############################################################################
  340. ### Substitution des variables spéciales devant l'être en une seule fois
  341. ### sur toutes les lignes d'une intervention (%randnick% et %randnick<index>%)
  342. ### $text est une liste d'une ou plusieurs réponses
  343.  ##############################################################################
  344. proc ::reanimator::substitute_special_vars_1st_pass {chan text} {
  345.     if { $text eq "!misfit!" } { return $text }
  346.     # Si %idle_time% ou %lastnick% sont utilisés dans l'intervention et que
  347.     # personne n'a encore parlé sur ce chan, ou si %lastnick% a quitté le chan,
  348.     # on arrête et on retourne un code d'erreur pour indiquer que cette
  349.     # intervention est inappropriée.
  350.     if { (([regsub -all {%(tcl_)?idle_time%} $text {&} text] != 0)
  351.         && ([::reanimator::idle_time $chan] eq "no activity"))
  352.         || (([regsub -all {%(tcl_)?lastnick%} $text {&} text] != 0)
  353.         && (([set last_activity [lindex $::reanimator::memory([md5 $chan]) 2]] eq "-")
  354.         || (($last_activity ne "-")
  355.         && (![onchan [lindex $::reanimator::memory([md5 $chan]) 1] $chan]))))
  356.     } then {
  357.         return "!misfit!"
  358.     }
  359.     # Liste de nicks des users présents sur le chan, sauf le nick de l'Eggdrop
  360.     set static_nicklist [lreplace [set nicklist [chanlist $chan]] [set index [lsearch -exact $nicklist $::nick]] $index]
  361.     # On exclut de la liste les users présents dans $randnick_exclusion_list
  362.     foreach excluded_user $::reanimator::randnick_exclusion_list {
  363.         set static_nicklist [lreplace $static_nicklist [set index [lsearch -nocase $static_nicklist $excluded_user]] $index]
  364.         if { [set user [hand2nick $excluded_user]] ne "" } {
  365.             set static_nicklist [lreplace $static_nicklist [set index [lsearch -nocase $static_nicklist $user]] $index]
  366.         }
  367.     }
  368.     # Remplacement des variables %randnick% et %tcl_randnick% par un nick
  369.     # aléatoire chaque fois différent
  370.     set num_thisvar [regsub -all {%(tcl_)?randnick%} $text {&} text]
  371.     if { $num_thisvar != 0 } {
  372.         # S'il ne reste personne dans la liste après avoir retiré le nick du bot et
  373.         # les nicks/handles de ceux qu'on exclut des %randnick%, alors on interromp
  374.         # la substitution et on retourne un code d'erreur
  375.         if { $static_nicklist eq "" } { return "!misfit!" }
  376.         set nicklist $static_nicklist
  377.         set num_users [llength $nicklist]
  378.         # Si on n'a pas plus de %randnick% à remplacer qu'il n'y a d'users
  379.         # sur le chan, on s'assure qu'un même nick ne sera pas utilisé plus
  380.         # d'une fois.
  381.         if { $num_thisvar <= $num_users } {
  382.             for { set counter 1 } { $counter <= $num_thisvar } { incr counter } {
  383.                 set num_remaining_users [llength $nicklist]
  384.                 set random_index [rand $num_remaining_users]
  385.                 if { ![regsub {%randnick%} $text [regsub -all {[\}\{]} [set chosen_randnick [lindex $nicklist $random_index]] {\\&}] text] } {
  386.                     regsub {%tcl_randnick%} $text [regsub -all {\W} $chosen_randnick {\\\\&}] text
  387.                 }
  388.                 set nicklist [lreplace $nicklist $random_index $random_index]
  389.             }
  390.         # Si on a plus de %randnick% à remplacer qu'il n'y a d'users sur le
  391.         # chan, on s'autorise à utiliser plusieurs fois le même nick,
  392.         # aléatoirement.
  393.         } else {
  394.             for { set counter 1 } { $counter <= $num_thisvar } { incr counter } {
  395.                 set random_index [rand $num_users]
  396.                 if { ![regsub {%randnick%} $text [regsub -all {[\}\{]} [set chosen_randnick [lindex $nicklist $random_index]] {\\&}] text] } {
  397.                     regsub {%tcl_randnick%} $text [regsub -all {\W} $chosen_randnick {\\\\&}] text
  398.                 }
  399.             }
  400.         }                      
  401.     }
  402.     # Remplacement des variables %randnick<index>% et %tcl_randnick<index>% par un
  403.     # nick aléatoire statique selon l'index.
  404.     # Combien de %randnick<index>% différents devra-t-on remplacer ?
  405.     set num_thisvar [llength [set replacement_list [lsort -unique [regexp -inline -all {%(?:tcl_)?randnick\d+%} $text]]]]
  406.     if { $num_thisvar != 0 } {
  407.         if { $static_nicklist eq "" } { return "!misfit!" }
  408.         set nicklist [::reanimator::randomize_list $static_nicklist]
  409.         set num_users [llength $nicklist]
  410.         # Si on n'a pas plus de %randnick<index>% différents à remplacer
  411.         # qu'il n'y a d'users sur le chan, on s'assure qu'un même nick ne
  412.         # sera pas utilisé plus d'une fois.
  413.         if { $num_thisvar <= $num_users } {
  414.             foreach randnick $replacement_list {
  415.                 set num_remaining_users [llength $nicklist]
  416.                 regexp {\d+} $randnick seed
  417.                 set seeded_index [expr {$seed % $num_remaining_users}]
  418.                 regsub -all "%tcl_randnick[set seed]%" $text [regsub -all {\W} [set chosen_randnick [lindex $nicklist $seeded_index]] {\\\\&}] text
  419.                 regsub -all "%randnick[set seed]%" $text [regsub -all {[\}\{]} $chosen_randnick {\\&}] text
  420.                 set nicklist [lreplace $nicklist $seeded_index $seeded_index]
  421.             }
  422.         # Si on a plus de %randnick<index>% à remplacer qu'il n'y a d'users sur le
  423.         # chan, on s'autorise à utiliser plusieurs fois le même nick,
  424.         # aléatoirement.
  425.         } else {
  426.             foreach randnick $replacement_list {
  427.                 regexp {\d+} $randnick seed
  428.                 set seeded_index [expr {$seed % $num_users}]
  429.                 regsub -all "%tcl_randnick[set seed]%" $text [regsub -all {\W} [set chosen_randnick [lindex $nicklist $seeded_index]] {\\\\&}] text
  430.                 regsub -all "%randnick[set seed]%" $text [regsub -all {[\}\{]} $chosen_randnick {\\&}] text
  431.             }
  432.         }
  433.     }
  434.     return $text
  435. }
  436.  
  437.  ##############################################################################
  438. ### Substitution des autres variables spéciales au moment de l'affichage.
  439. ### $text est une string
  440.  ##############################################################################
  441. proc ::reanimator::substitute_special_vars_2nd_pass {chan text} {
  442.     if { $text eq "!misfit!" } { return $text }
  443.     regsub -all %idle_time% $text [::reanimator::idle_time $chan] text
  444.     regsub -all %lastnick% $text [regsub -all {\W} [lindex $::reanimator::memory([md5 $chan]) 1] {\\&}] text
  445.     regsub -all %chan% $text [regsub -all {[\[\]\{\}\$\"\\]} $chan {\\&}] text ; # "
  446.     regsub -all %botnick% $text [regsub -all {\W} $::nick {\\&}] text
  447.     regsub -all %hour% $text [set hour [strftime %H [unixtime]]] text
  448.     regsub -all %hour_short% $text [if { $hour != 00 } { set dummy [::tcl::string::trimleft $hour 0] } { set dummy 0 }] text
  449.     regsub -all %minutes% $text [set minutes [strftime %M [unixtime]]] text
  450.     regsub -all %minutes_short% $text [if { $minutes != 00 } { set dummy [::tcl::string::trimleft $minutes 0] } { set dummy 0 }] text
  451.     regsub -all %seconds% $text [set seconds [strftime %S [unixtime]]] text
  452.     regsub -all %seconds_short% $text [if { $seconds != 00 } { set dummy [::tcl::string::trimleft $seconds 0] } { set dummy 0 }] text
  453.     regsub -all %day_num% $text [strftime %d [unixtime]] text
  454.     regsub -all %day% $text [::tcl::string::map -nocase {Mon lundi Tue mardi Wed mercredi Thu jeudi Fri vendredi Sat samedi Sun dimanche} [strftime "%a" [unixtime]]] text
  455.     regsub -all %month_num% $text [strftime %m [unixtime]] text
  456.     regsub -all %month% $text [::tcl::string::map {Jan janvier Feb février Mar mars Apr avril May mai Jun juin Jul juillet Aou août Sep septembre Oct octobre Nov novembre Dec décembre} [strftime %b [unixtime]]] text
  457.     regsub -all %year% $text [strftime %Y [unixtime]] text
  458.     return $text
  459. }
  460.  
  461.  ##############################################################################
  462. ### Surveillance des changements de nick de la dernière personne ayant parlé
  463. ### afin de tenir %lastnick% à jour
  464.  ##############################################################################
  465. proc ::reanimator::survey_lastnick_change {nick host hand chan newnick} {
  466.     if { ![channel get $chan reanimator] } { return }
  467.     if { $nick eq [lindex $::reanimator::memory([set hash [md5 [::tcl::string::tolower $chan]]]) 1] } {
  468.         set ::reanimator::memory($hash) [list [lindex $::reanimator::memory($hash) 0] $newnick [lindex $::reanimator::memory($hash) 2] [lindex $::reanimator::memory($hash) 3]]
  469.         if { $::reanimator::DEBUGMODE >= 1 } {
  470.             putlog [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - debug\]\003 $nick est la dernière personne ayant parlé sur $chan (%lastnick%) et vient juste de changer de nick pour $newnick. Modification de l'enregistrement \00314\$::reanimator::memory($hash) \{[set ::reanimator::memory($hash)]\}"]
  471.         }
  472.     }
  473. }
  474.  
  475.  ##############################################################################
  476. ### Retourne le temps d'idle d'un chan en secondes OU en minutes OU en heures
  477. ### car selon le temps écoulé, le besoin de précision varie
  478.  ##############################################################################
  479. proc ::reanimator::idle_time {chan} {
  480.     set hash [md5 $chan]
  481.     set last_activity [lindex $::reanimator::memory($hash) 2]
  482.     if { $last_activity eq "-" } { return "no activity" }
  483.     set idle_time [expr {[unixtime] - $last_activity}]
  484.     if { $idle_time < 60 } {
  485.         return "$idle_time [::reanimator::plural $idle_time "seconde" "secondes"]"
  486.     } elseif { $idle_time < 3600 } {
  487.         set value [expr {abs($idle_time / 60)}]
  488.         return "$value [::reanimator::plural $value "minute" "minutes"]"
  489.     } else {
  490.         set value [expr {abs($idle_time / 3600)}]
  491.         return "$value [::reanimator::plural $value "heure" "heures"]"
  492.     }
  493. }
  494.  
  495.  ##############################################################################
  496. ### Traitement de la file d'attente de parole
  497.  ##############################################################################
  498. proc ::reanimator::delayed_talk {} {
  499.     # si la file d'attente de réponses est vide, on arrête
  500.     if { ![llength $::reanimator::talk_queue] } {
  501.         variable delayed_talk_running 0
  502.         return
  503.     } else {
  504.         variable delayed_talk_running 1
  505.     }
  506.     set raw_text [lindex $::reanimator::talk_queue 0 1]
  507.     set chan [lindex $::reanimator::talk_queue 0 0]
  508.     set first_word ""
  509.     regexp {^([^\s]+)\s(.*)} $raw_text {} first_word leftovers
  510.     switch -exact -- [::tcl::string::tolower $first_word] {
  511.         "/putserv" {
  512.             # le 1er argument est le type (0=/putserv 1=normal 2=/me 3=/tcl)
  513.             # le 2ème argument signifie "ajouter au log ?" (0=non 1=oui)
  514.             ::reanimator::display_response 0 $chan $leftovers
  515.         }
  516.         "/me" {
  517.             set delay [expr {round(($::reanimator::reply_speed_coeff * sqrt([::tcl::string::length $leftovers])) + $::reanimator::reply_speed_offset) * 1000}]
  518.             after $delay [list ::reanimator::display_response 1 $chan $leftovers]
  519.             if { $::reanimator::DEBUGMODE >= 1 } { putlog [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - debug\]\003 after [expr {$delay / 1000}] \00314--$chan-->\003 $leftovers"] }
  520.         }
  521.         "/tcl" {
  522.             ::reanimator::display_response 2 $chan $leftovers
  523.         }
  524.         default {
  525.             set delay [expr {round(($::reanimator::reply_speed_coeff * sqrt([::tcl::string::length $raw_text])) + $::reanimator::reply_speed_offset) * 1000}]
  526.             after $delay [list ::reanimator::display_response 3 $chan $raw_text]
  527.             if { $::reanimator::DEBUGMODE >= 1 } { putlog [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - debug\]\003 after [expr {$delay / 1000}] \00314--$chan-->\003 $raw_text"] }
  528.         }
  529.     }
  530.     return
  531. }
  532.  
  533.  ##############################################################################
  534. ### Affichage d'une réponse sur un chan
  535. ### type : 0 = /putserv   1 = /me   2 = /tcl   3 = normal
  536.  ##############################################################################
  537. proc ::reanimator::display_response {type chan text} {
  538.     switch -exact -- $type {
  539.         0 {
  540.             set output "putserv \"[::reanimator::substitute_special_vars_2nd_pass $chan $text]\""
  541.         }
  542.         1 {
  543.             set output "puthelp \"PRIVMSG [regsub -all {\W} $chan {\\&}] :\\001ACTION [::reanimator::substitute_special_vars_2nd_pass $chan $text]\\001\""
  544.             putloglev p $chan "* $::nick $text"
  545.         }
  546.         2 {
  547.             set output [::reanimator::substitute_special_vars_2nd_pass $chan $text]
  548.         }
  549.         3 {
  550.             set output "puthelp \"PRIVMSG [regsub -all {\W} $chan {\\&}] :[::reanimator::substitute_special_vars_2nd_pass $chan $text]\""
  551.             putloglev p $chan "<$::nick> $text"
  552.         }
  553.     }
  554.     if { [catch {uplevel 1 $output}] } {
  555.         putloglev o * [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - erreur\]\003 L'intervention suivante provoque une erreur et a été ignorée :\00314 $output"]
  556.         putloglev o * [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - erreur\]\003 Problème rencontré :\00314 [lindex [split $::errorInfo "\n"] 0]"]
  557.     }
  558.     # on élimine la 1ère réponse de la file d'attente car elle a été traitée
  559.     set ::reanimator::talk_queue [lreplace $::reanimator::talk_queue 0 0]
  560.     ::reanimator::delayed_talk
  561.     return
  562. }
  563.  
  564.  ##############################################################################
  565. ### Accord au singulier ou au pluriel
  566.  ##############################################################################
  567. proc ::reanimator::plural {value singular plural} {
  568.     if { ($value >= 2) || ($value <= -2) } { return $plural } { return $singular }
  569. }
  570.  
  571.  ##############################################################################
  572. ### Mélange aléatoire des éléments d'une liste
  573. ### Cette procédure provient de http://wiki.tcl.tk/941 (shuffle6)
  574.  ##############################################################################
  575. proc ::reanimator::randomize_list {data} {
  576.     set n [llength $data]
  577.     for { set i 1 } { $i < $n } { incr i } {
  578.         set j [expr {int(rand() * $n)}]
  579.         set temp [lindex $data $i]
  580.         lset data $i [lindex $data $j]
  581.         lset data $j $temp
  582.     }
  583.     return $data
  584. }
  585.  
  586.  ##############################################################################
  587. ### Vérifie si un chan nécessite d'être réanimé
  588. ### Structure de l'array memory($chan_hash) :
  589. ### <timestamp> <dernier nick ayant parlé> <timestamp dernière fois que qq'un a parlé> <init/activity/revived>
  590.  ##############################################################################
  591. proc ::reanimator::check_pulse {min hour day month year} {
  592.     foreach chan [channels] {
  593.         if { [channel get $chan reanimator] } {
  594.             set hash [md5 [set lowerchan [::tcl::string::tolower $chan]]]
  595.             # aucun enregistrement n'est mémorisé pour $chan, on en crée un
  596.             if { ![::tcl::info::exists ::reanimator::memory($hash)] } {
  597.                 set ::reanimator::memory($hash) [list [unixtime] - - init]
  598.                 if { $::reanimator::DEBUGMODE >= 1 } { putlog [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - debug\]\003 Création de l'enregistrement \00314\$::reanimator::memory($hash) \{[set ::reanimator::memory($hash)]\}"] }
  599.             # un enregistrement existe déjà pour $chan;
  600.             # si le chan n'a pas déjà été réanimé et que $revive_after minutes se
  601.             # sont écoulées, ou si le chan a déjà été réanimé et que
  602.             # $revive_again_after minutes se sont écoulées, on le réanime
  603.             } elseif {
  604.                 (([lindex $::reanimator::memory($hash) 3] ne "revived")
  605.                  && ([lindex $::reanimator::memory($hash) 0] + $::reanimator::revive_after <= [unixtime]))
  606.                 || (([lindex $::reanimator::memory($hash) 3] eq "revived")
  607.                  && ([lindex $::reanimator::memory($hash) 0] + $::reanimator::revive_again_after <= [unixtime]))
  608.             } then {
  609.                 if { $::reanimator::DEBUGMODE >= 1 } {
  610.                     if { ([lindex $::reanimator::memory($hash) 3] ne "revived") && ([lindex $::reanimator::memory($hash) 0] + $::reanimator::revive_after <= [unixtime]) } {
  611.                         putlog "\00304\[$::reanimator::scriptname - DEBUG\]\003 Réanimation de $chan - 1ère intervention."
  612.                     } elseif { ([lindex $::reanimator::memory($hash) 3] eq "revived") && ([lindex $::reanimator::memory($hash) 0] + $::reanimator::revive_again_after <= [unixtime]) } {
  613.                         putlog "\00304\[$::reanimator::scriptname - DEBUG\]\003 Réanimation de $chan - nouvelle tentative."
  614.                     }
  615.                 }
  616.                 ::reanimator::defibrillator $lowerchan
  617.                 set ::reanimator::memory($hash) [list [unixtime] [lindex $::reanimator::memory($hash) 1] [lindex $::reanimator::memory($hash) 2] revived]
  618.                 if { $::reanimator::DEBUGMODE >= 1 } { putlog [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - debug\]\003 Modification de l'enregistrement \00314\$::reanimator::memory($hash) \{[set ::reanimator::memory($hash)]\}"] }
  619.             }
  620.         }
  621.     }
  622. }
  623.  
  624.  ##############################################################################
  625. ### De l'activité a été détectée sur un chan
  626.  ##############################################################################
  627. proc ::reanimator::pub_life_sign_detected {nick host hand chan text} {
  628.     ::reanimator::life_sign_detected $nick $host $hand $chan $text
  629. }
  630. proc ::reanimator::ctcp_life_sign_detected {nick host hand target ctcp_type text} {
  631.     if { [validchan $target] } {
  632.         ::reanimator::life_sign_detected $nick $host $hand $target $text
  633.     }
  634. }
  635. proc ::reanimator::life_sign_detected {nick host hand chan text} {
  636.     if { ([channel get $chan reanimator])
  637.         && ([lsearch -nocase $::reanimator::ignores $nick] == -1)
  638.         && ([lsearch -nocase -exact $::reanimator::ignores $hand] == -1)
  639.     } then {
  640.         set ::reanimator::memory([md5 [::tcl::string::tolower $chan]]) [list [unixtime] $nick [unixtime] activity]
  641.         if { $::reanimator::DEBUGMODE == 2 } { putlog [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - debug\]\003 Activité détectée de la part de $nick sur $chan. Modification de l'enregistrement \00314\$::reanimator::memory([set hash [md5 [::tcl::string::tolower $chan]]]) \{[set ::reanimator::memory($hash)]\}"] }
  642.     }
  643. }
  644.  
  645.  ##############################################################################
  646. ### Gestion des couleurs; filtrage des codes de couleur/gras/soulignement si le
  647. ### mode +c est détecté sur le chan, ou si la couleur est désactivée
  648. ### manuellement
  649.  ##############################################################################
  650. proc ::reanimator::filter_styles_if_req {chan text} {
  651.     if { ($::reanimator::monochrome) || (($chan ne "-") && ([::tcl::string::match *c* [lindex [split [getchanmode $chan]] 0]])) } {
  652.         return [regsub -all {\017} [stripcodes abcgru $text] ""]
  653.     } else {
  654.         return $text
  655.     }
  656. }
  657.  
  658.  ###############################################################################
  659. ### Construction des listes d'index aléatoires servant à éviter la répétition
  660. ### d'une intervention tant que tous les autres n'ont pas été utilisées.
  661.  ###############################################################################
  662. proc ::reanimator::build_random_indexes {chan} {
  663.     ::tcl::dict::set ::reanimator::random_indexes $chan [::reanimator::randomize_list [lsearch -all $::reanimator::database "*"]]
  664. }
  665.  
  666.  ##############################################################################
  667. ### Commande !reanimator_test_output permettant d'exécuter l'intervention
  668. ### passée en argument
  669.  ##############################################################################
  670. proc ::reanimator::test_output {nick host hand chan text} {
  671.     if { [catch {set textlistlength [llength $text]}] } {
  672.         puthelp [::reanimator::filter_styles_if_req $chan "PRIVMSG $chan :\00304\[$::reanimator::scriptname - erreur\]\003 les \{ et \} ne sont pas équilibrés."]
  673.         return
  674.     }
  675.     if { ($text eq "") || ($textlistlength > 1) } {
  676.         puthelp [::reanimator::filter_styles_if_req $chan "PRIVMSG $chan :\037Syntaxe\037 : \002!reanimator_test\002 \{\{ligne 1\}\00314\[\003 \{ligne 2\}\00314\[\003 \{...\}\00314\]\]\003\} \00307|\003 Permet de tester en direct l'intervention spécifiée."]
  677.         return
  678.     }
  679.     # Si aucun enregistrement n'existe pour $chan, on en crée un
  680.     if { ![::tcl::info::exists ::reanimator::memory([set hash [md5 [set lowerchan [::tcl::string::tolower $chan]]]])] } {
  681.         set ::reanimator::memory($hash) [list [unixtime] - - init]
  682.         if { $::reanimator::DEBUGMODE >= 1 } { putlog [::reanimator::filter_styles_if_req - "\00304\[$::reanimator::scriptname - debug\]\003 Création de l'enregistrement \00314\$::reanimator::memory($hash) \{[set ::reanimator::memory($hash)]\}"] }
  683.     }
  684.     foreach line {*}[::reanimator::substitute_special_vars_1st_pass $lowerchan $text] {
  685.         regexp {^([^\s]+)\s} $line {} first_word
  686.         # hormis pour la commande /tcl, on neutralise les caractères qui choquent
  687.         # Tcl, à l'exception des codes de couleur/gras/...
  688.         if { (![::tcl::info::exists first_word]) || ($first_word ne "/tcl") } {
  689.             regsub -all {\\\\([\}\{])} [regsub -all {(?!\\002|\\003|\\022|\\037|\\026|\\017)[\$[\[\]"\\]} $line {\\&}] {\1} line ; # "
  690.         }
  691.         # Filtrage des codes couleur/gras/... si le mode monochrome est activé ou
  692.         # si le flag +c est détecté sur le chan.
  693.         # Remarque : stripcodes ne fonctionne pas du fait que les \ ont été
  694.         # neutralisés
  695.         if { ($::reanimator::monochrome) || ([::tcl::string::match *c* [lindex [split [getchanmode $chan]] 0]]) } {
  696.              regsub -all {\\003[0-9]{0,2}(,[0-9]{0,2})?|\\017|\\037|\\002|\\026|\\006|\\007} $line "" line
  697.         }
  698.         lappend ::reanimator::talk_queue [list $lowerchan $line]
  699.     }
  700.     if { !$::reanimator::delayed_talk_running } { ::reanimator::delayed_talk }
  701. }
  702.  
  703.  ##############################################################################
  704. ### commande !reanimator_stats : affiche le nombre d'interventions dans la base
  705. ### de données, ainsi que quelques autres informations sur les réglages du
  706. ### script
  707.  ##############################################################################
  708. proc ::reanimator::stats {nick host hand chan arg} {
  709.     puthelp [::reanimator::filter_styles_if_req $chan "PRIVMSG $chan :J'interviendrai si personne ne parle pendant \002[expr {$::reanimator::revive_after / 60}]\002 minutes, puis à nouveau toutes les \002[expr {$::reanimator::revive_again_after / 60}]\002 minutes. Ma base de données contient actuellement \002[set num_interventions [llength $::reanimator::database]]\002 [::reanimator::plural $num_interventions "intervention" "interventions"]."]
  710. }
  711.  
  712.  ##############################################################################
  713. ### Post-initialisation
  714.  ##############################################################################
  715. ::reanimator::check_pulse  - - - - -
  716.  
  717.  ##############################################################################
  718. ### Binds
  719.  ##############################################################################
  720. bind evnt - prerehash ::reanimator::uninstall
  721. bind time - "* * * * *" ::reanimator::check_pulse
  722. bind nick - * ::reanimator::survey_lastnick_change
  723. bind pubm - * ::reanimator::pub_life_sign_detected
  724. bind ctcp - ACTION ::reanimator::ctcp_life_sign_detected
  725. bind pub n !reanimator_test ::reanimator::test_output
  726. bind pub n !reanimator_stats ::reanimator::stats
  727.  
  728.  
  729. putlog "$::reanimator::scriptname v$::reanimator::version (©2013-2016 Menz Agitat) a été chargé."
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement