Tag Archive for chat

Chat system example

<?php
/**
 * Add a message to the chat
 * @param Redis $redis Redis connection handler
 * @param String $message message to add
 * @return void
 */
function addMessage($redis, $message) {
	$redis->lPush("chat", $message);
	if($redis->lLen("chat") > 100) {
		$redis->rPop("chat");
	}
}

source

moxquizz update (german)

##
### moxquizz.tcl -- quizzbot for eggdrop 1.6.9+
##
### Author: Moxon <moxon@meta-x.de> (AKA Sascha Lüdecke)
##
### Credits:
##       - Artwork was done with heavy support of Michee <Michee@sonnet.de>
##       - Julika loved to discuss and suggested many things.
##       - Imran Ghory provided more than 600 english questions.
##       - Questions have been edited by Michee, Julika, Tobac, Imran and
##         Klinikai_Eset
##       - ManInBlack for supplemental scripting
##       - numerous others, see the README for a more complete list.
##         If you are missing, please tell me!
##
### Copyright (C) 2000 Moxon AKA Sascha Lüdecke
##
##  This program is free software; you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation; either version 2 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program; if not, write to the Free Software
##  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
###
## $Id: moxquizz.tcl,v 1.175 2002/07/05 19:21:26 chat Exp $


###########################################################################
###########################################################################
###########################################################################

########################
### typ's mod config ###
########################

#Wieviel Sekunden sollen Schätzfragen offen sein?
set schaetztime 15

#Soll !vok erlaubt sein? (1=ja,2=nein)
set allow_vok 1

#Soll !halt erlaubt sein? (1=ja,2=nein)
set allow_halt 1

#Soll das Anti-Highlighting aktiviert sein? (1=ja,2=nein)
set allow_antihl 1

#Soll das gelbe Design aktiviert sein? (1=ja,2=nein)
set go_yellow 0

#Sollen statistische Daten im Web veröffentlicht werden? (1=ja,2=nein)
set allow_web 1

#Sollen Zeitrekorde gespeichert werden? (1=ja,2=nein)
set allow_rec 1

#Soll der Bot jeden Tag einmal neu starten? (1=ja,2=nein)
set daily_restart 0

########################
###  typ's mod info  ###
########################

# 1. Schätzfragen
#  Schätzfragen müssen als Kategorie "Category: Schätzfragen" haben, ansonsten werden sie wie normale Quizfragen behandelt.
#  Die Antworten dürfen lediglich aus arabischen Zahlen (ohne Trennpunkte) sein.

# 2. Ratefragen
#  Ratefragen müssen als Kategorie "Category: Ratefragen" haben, ansonsten werden sie wie normale Quizfragen behandelt.
#  Die Antworten müssen folgendes Format haben: Antwort1*Antwort2*Antwort3
#  Das Ratefragen-Script basiert auf dem KAOS-Script von Mark A. Day.

# 3. A/M
#  A/M steht für Anschläge pro Minute

# 4. Web-Statistiken
#  Soweit von Dir erlaubt, sendet der QuizBot informationen an <a href="http://moxquiz.bplaced.net/homepage/" >http://moxquiz.bplaced.net/homepage/</a>

# 5. Support
#  Support gibt es im MoxQuizz-Forum unter <a href="http://www.moxquizz.de/forum" >http://www.moxquizz.de/forum</a> oder im #quiz.de @ irc.gamesurge.net


########################
###   new commands   ###
########################

#!vok - Zeigt die Antwort ohne Vokale
#!halt - Hält den Bot an

#!alltimes - Zeigt die ewige Rangliste an

#!server - Zeigt den Server, zu dem der Bot verbunden ist
#!time - Zeigt Deine Spieldauer

#!rehash - OPs only
#!restart - OPs only


###########################################################################
###########################################################################
###########################################################################


## Version:
set version_moxquizz "0.8.1 {type:mod von <a href="http://moxquiz.bplaced.net/homepage/" >http://moxquiz.bplaced.net/homepage/</a>}"

package require msgcat
package require http

namespace import -force msgcat::*

###########################################################################
##
## ATTENTION:
##
## Defaults for bot configuration.  Don't edit here, edit the file
## moxquizz.rc instead!
##
###########################################################################


# system stuff
variable quizbasedir        moxquizz
variable datadir            $quizbasedir/quizdata
variable configfile         $quizbasedir/moxquizz.rc
variable intldir            $quizbasedir/intl

variable rankfile           $datadir/rank.data
variable allstarsfile       $datadir/rankallstars.data
variable statsfile          $datadir/stats.data
variable userqfile          $datadir/questions.user.new
variable commentsfile       $datadir/comments.txt

variable quizhelp

# these will be searched in $intldir/$quizconf(language)
variable channeltipfile     channeltips.txt
variable channelrulesfile   channelrules.txt
variable pricesfile         prices.txt
variable helpfile           help.txt


#
# Configuration map
#
variable quizconf

set quizconf(quizchannel)        "#quiz"
set quizconf(quizloglevel)       1

# several global numbers
set quizconf(maxranklines)       100
set quizconf(tipcycle)           5
set quizconf(useractivetime)     240
set quizconf(userqbufferlength)  20
set quizconf(winscore)           30
set quizconf(overrunlimit)       29

# timer delays in seconds
set quizconf(askdelay)           12
set quizconf(tipdelay)           14

# safety features and other configs
set quizconf(lastwinner_restriction)  no
set quizconf(lastwinner_max_games)    4
set quizconf(overrun_protection)      no
set quizconf(colorize)                yes
set quizconf(monthly_allstars)        no
set quizconf(channeltips)             yes
set quizconf(pausemoderated)          no
set quizconf(userquestions)           yes
set quizconf(msgwhisper)              no
set quizconf(channelrules)            yes
set quizconf(prices)                  yes
set quizconf(stripumlauts)            no
set quizconf(statslog)                no
set quizconf(aftergameaction)         newgame

set quizconf(language)                de


##
###########################################################################

##
## stuff for the game state
##

#typ
set ctcp-version "MoxQuizz für #Quiz.de @ irc.GameSurge.net"
variable answerarray
variable schaetzarray

variable schaetzend ""
variable schaetzwert ""
variable timetypasked [clock clicks -milliseconds]

variable subexp ""
variable bestscore 0

# values = stopped, paused, asked, waittoask, halted
variable quizstate "halted"
variable statepaused ""
variable statemoderated ""
variable usergame 0
variable timeasked [unixtime]
variable revoltmax 0
# values = newgame, stop, halt, exit
variable aftergame $quizconf(aftergameaction)
variable channeltips ""
variable channelrules ""
variable prices ""

#
# variables for the ranks and user handling
#
variable timerankreset [unixtime]
variable userlist
variable allstarsarray
variable revoltlist ""
variable lastsolver ""
variable lastsolvercount 0
variable lastwinner ""
variable lastwinnercount 0
variable allstars_starttime 0
variable ignore_for_userquest ""

#
# stuff for the question
#
variable tiplist ""
variable theq
variable qnumber 0
variable qnum_thisgame 0
variable userqnumber 0
variable tipno 0
variable qlist ""
variable qlistorder ""
variable userqlist ""

#
# doesn't fit elsewhere
#
variable whisperprefix "NOTICE"
variable statsfilefd "closed"

##################################################
## bindings

# bot running status
bind dcc P !init moxquiz_init
bind dcc P !stop moxquiz_stop
bind dcc P !halt moxquiz_halt
bind dcc P !pause moxquiz_pause
bind dcc P !cont moxquiz_cont
bind dcc P !reset moxquiz_reset
bind dcc m !exit moxquiz_exit
bind dcc m !aftergame moxquiz_aftergame

# bot speaking and hopping stuff
bind dcc P !say moxquiz_say
bind dcc P !act moxquiz_action
bind dcc m !allsay moxquiz_say_everywhere
bind dcc m !allact moxquiz_action_everywhere
bind dcc Q !join moxquiz_join
bind dcc Q !part moxquiz_part
bind dcc Q !quizto moxquiz_quizto
bind dcc Q !quizleave moxquiz_quizleave

# commands for the questions
bind dcc P !solve moxquiz_solve
bind dcc P !tip moxquiz_tip
bind dcc P !skipuserquest moxquiz_skipuserquest
bind dcc Q !setscore moxquiz_set_score

bind dcc m !qsave moxquiz_saveuserquests
bind dcc Q !reload moxquiz_reload


# status and configuration
bind dcc P !status moxquiz_status
bind dcc m !load moxquiz_config_load
bind dcc m !save moxquiz_config_save
bind dcc m !set moxquiz_config_set

# userquest and other user (public) commands
bind pubm - * moxquiz_pubm
bind pub - !ask moxquiz_ask
bind pub - .ask moxquiz_ask
bind pub - !quiz moxquiz_ask
bind pub - .quiz moxquiz_ask
bind pub - !start moxquiz_ask
bind pub - .start moxquiz_ask

bind pub - !revolt moxquiz_user_revolt
bind pub - !end moxquiz_user_revolt

bind msg - !userquest moxquiz_userquest
bind msg - !usercancel moxquiz_usercancel
bind msg - !usertip moxquiz_usertip
bind msg - !usersolve moxquiz_usersolve
bind pub P !nuq moxquiz_userquest_ignore
bind pub P !uq moxquiz_userquest_unignore
bind pub P !listnuq moxquiz_userquest_listignores
bind pub P !clearnuq moxquiz_userquest_clearignores

bind msg - !qhelp moxquiz_help
bind pub - !qhelp moxquiz_pub_help
bind pub - !score moxquiz_pub_score
bind pub - !rank moxquiz_pub_rank
bind pub - !allstars moxquiz_pub_allstars
bind pub - !comment moxquiz_pub_comment
bind pub - !fehler moxquiz_pub_comment
bind dcc - !comment moxquiz_dcc_comment
bind msg - !rules moxquiz_rules
bind pub - !rules moxquiz_pub_rules
bind msg - !version moxquiz_version
bind pub - !version moxquiz_pub_version

# mini funstuff
bind pub - !hi moxquiz_pub_hi
#bind ctcp - action moxquiz_purr

# commands to manage players and rank
bind dcc P !allstars moxquiz_allstars
bind dcc m !allstarssend moxquiz_allstars_send
bind dcc m !allstarsload moxquiz_allstars_load
bind dcc P !rank moxquiz_rank
bind dcc Q !rankdelete moxquiz_rank_delete
bind dcc m !rankload moxquiz_rank_load
bind dcc m !ranksave moxquiz_rank_save
bind dcc Q !rankreset moxquiz_rank_reset
bind dcc Q !rankset moxquiz_rank_set


# Some events the bot reacts on
bind nick - * moxquiz_on_nickchanged
bind join - * moxquiz_on_joined
bind mode - "*m" moxquiz_on_moderated
bind evnt - prerehash mx_event
bind evnt - rehash mx_event

## DEBUG
bind dcc n !colors moxquiz_colors

###########################################################################
#
# bot running commands
#
###########################################################################

## reset game
proc moxquiz_reset {handle idx arg} {
global quizstate
moxquiz_stop $handle $idx $arg
moxquiz_rank_reset $handle $idx $arg
moxquiz_init $handle $idx $arg
}

## initialize
proc moxquiz_init {handle idx arg} {
global qlist version_moxquizz banner bannerspace quizstate
global quizconf aftergame

set quizstate "halted"
set aftergame $quizconf(aftergameaction)
if {$quizconf(quizchannel) != ""} {
mxirc_say $quizconf(quizchannel) [mc "%sHello!  I am a MoxQuizz version %s and ready to squeeze your brain!" "[banner] [botcolor txt]" "[col bold]$version_moxquizz[col bold][botcolor txt]"]
mxirc_say $quizconf(quizchannel) [mc "%s%d questions in database, just %s!ask%s.  Report bugs and suggestions to <a href="mailto:moxon@meta-x.de">moxon@meta-x.de</a>" "[bannerspace] [botcolor txt]" [llength $qlist]  [col bold] "[col bold][botcolor txt]"]
mx_log "--- Game initialized"
} else {
mxirc_dcc $idx "ERROR: quizchannel is set to an empty string, use .!quizto to set one."
}
return 1
}

## stop
## stop everything and kill all timers
proc moxquiz_stop {handle idx arg} {
global quizstate banner bannerspace
global quizconf
variable t
variable prefix [banner]


## called directly?
if {[info level] != 1} {
set prefix [bannerspace]
} else {
set prefix [banner]
}

set quizstate "stopped"

## kill timers
foreach t [utimers] {
if {[lindex $t 1] == "mx_timer_ask" || [lindex $t 1] == "mx_timer_tip"} {
killutimer [lindex $t 2]
}
}

mx_log "--- Game stopped."
mxirc_say $quizconf(quizchannel) [mc "%s %sQuiz stopped." $prefix [botcolor boldtxt]]
return 1
}


## halt
## halt everything and kill all timers
proc moxquiz_halt {handle idx arg} {
global quizstate banner bannerspace
global quizconf

variable t
variable prefix [banner]

## called directly?
if {[info level] != 1} {
set prefix [bannerspace]
} else {
set prefix [banner]
}

set quizstate "halted"

## kill timers
foreach t [utimers] {
if {[lindex $t 1] == "mx_timer_ask" || [lindex $t 1] == "mx_timer_tip"} {
killutimer [lindex $t 2]
}
}

mx_log "--- Game halted."
mxirc_say $quizconf(quizchannel) [mc "%s %sQuiz halted.  Say !ask for new questions." $prefix [botcolor boldtxt]]
utimer 5 mx_restart
return 1
}


## reload questions
proc moxquiz_reload {handle idx arg} {
global qlist quizconf
global datadir

variable alist ""
variable banks
variable suffix

set arg [string trim $arg]
if {$arg == ""} {
# get question files
set alist [glob -nocomplain "$datadir/questions.*"]

# get suffixes
foreach file $alist {
regexp "^.*.([^.]+)$" $file foo suffix
set banks($suffix) 1
}

# report them
mxirc_dcc $idx "There are the following question banks available (current: $quizconf(questionset)): [lsort [array names banks]]"
} else {
if {[mx_read_questions $arg] != 0} {
mxirc_dcc $idx "There was an error reading files for $arg."
mxirc_dcc $idx "There are [llength $qlist] questions available."
} else {
mxirc_dcc $idx "Reloaded database, [llength $qlist] questions."
set quizconf(questionset) $arg
}
}

return 1
}

## pause
proc moxquiz_pause {handle idx arg} {
global quizstate statepaused banner timeasked
global quizconf

variable qwasopen "."

if {[regexp "(halted|paused)" $quizstate]} {
mxirc_dcc $idx "Quiz state is $quizstate.  Command ignored."
} else {
if {$quizstate == "asked"} {
foreach t [utimers] {
if {[lindex $t 1] == "mx_timer_tip"} {
killutimer [lindex $t 2]
}
}
set qwasopen [mc " after %s." [mx_duration $timeasked]]
} elseif {$quizstate == "waittoask"} {
foreach t [utimers] {
if {[lindex $t 1] == "mx_timer_ask"} {
killutimer [lindex $t 2]
}
}
}
set statepaused $quizstate
set quizstate "paused"
mx_log "--- Game paused$qwasopen  Quiz state was: $statepaused"
mxirc_say $quizconf(quizchannel) [mc "%sQuiz paused%s" "[banner] [botcolor boldtxt]" $qwasopen]
}
return 1
}


## continue
proc moxquiz_cont {handle idx arg} {
global quizstate banner bannerspace timeasked
global theq statepaused usergame statemoderated
global quizconf

if {$quizstate != "paused"} {
mxirc_dcc $idx "Game not paused, command ignored."
} else {
if {$statepaused == "asked"} {
if {$usergame == 1} {
set txt [mc "%sQuiz continued.  The user question open since %s, worth %d point(s):" "[banner] [botcolor boldtxt]" [mx_duration $timeasked] $theq(Score)]
} else {
set txt [mc "%sQuiz continued.  The question open since %s, worth %d point(s):" "[banner] [botcolor boldtxt]" [mx_duration $timeasked] $theq(Score)]
}
mxirc_say $quizconf(quizchannel) $txt
mxirc_say $quizconf(quizchannel) "[bannerspace] [botcolor question]$theq(Question)"
utimer $quizconf(tipdelay) mx_timer_tip
} else {
mxirc_say $quizconf(quizchannel) [mc "%sQuiz continued.  Since there is no open question, a new one will be asked." "[banner] [botcolor boldtxt]"]
utimer 3 mx_timer_ask
}
set quizstate $statepaused
set statepaused ""
set statemoderated ""
mx_log "--- Game continued."
}
return 1
}

## show module status
proc moxquiz_status {handle idx arg} {
global quizstate statepaused qlist banner version_moxquizz userlist
global timeasked uptime
global usergame userqlist theq qnumber
global qnum_thisgame aftergame

global quizconf

variable askleft 0 rankleft 0 tipleft 0
variable txt
variable chansjoined ""

## banner and where I am
set txt "I am [mx_strip_colors [banner]] version $version_moxquizz, up for [mx_duration $uptime]"
if {$quizconf(quizchannel) == ""} {
set txt "$txt, not quizzing on any channel."
} else {
set txt "$txt, quizzing on channel "$quizconf(quizchannel)"."
}
mxirc_dcc $idx $txt

mxirc_dcc $idx "I know the channels [channels]."

foreach chan [channels] {
if {[botonchan $chan]} {
set chansjoined "$chansjoined $chan"
}
}
if {$chansjoined == ""} {
set chansjoined " none"
}
mxirc_dcc $idx "I currently joined:$chansjoined."

if {$quizstate == "asked" || $statepaused == "asked"} {
## Game running?  User game?
set txt "There is a"
if {$usergame == 1} {
set txt "$txt user"
}
set txt "$txt game running."
if {[mx_userquests_available]} {
set txt "$txt  [mx_userquests_available] user quests scheduled."
} else {
set txt "$txt  No user quest is scheduled."
}
set txt "$txt  Quiz state is: $quizstate."
mxirc_dcc $idx $txt

## Open question?  Quiz state?
set txt "The"
if {[info exists theq(Level)]} {
set txt "$txt level $theq(Level)"
}
set txt "$txt question no. $qnum_thisgame is:"
if {[info exists theq(Category)]} {
set txt "$txt ($theq(Category))"
}
mxirc_dcc $idx "$txt "$theq(Question)" open for [mx_duration $timeasked], worth $theq(Score) points."
} else {
## no open question, no game running
set txt "There is no question open."
set txt "$txt  Quiz state is: $quizstate."
if {[mx_userquests_available]} {
set txt "$txt  [mx_userquests_available] user quests scheduled."
} else {
set txt "$txt  No user quest is scheduled."
}
mxirc_dcc $idx $txt
}

mxirc_dcc $idx "Action after game won: $aftergame"

foreach t [utimers] {
if {[lindex $t 1] == "mx_timer_ask"} {
set askleft [lindex $t 0]
}
if {[lindex $t 1] == "mx_timer_tip"} {
set tipleft [lindex $t 0]
}
}

mxirc_dcc $idx "Tipdelay: $quizconf(tipdelay) ($tipleft)  Askdelay: $quizconf(askdelay) ($askleft) Tipcycle: $quizconf(tipcycle)"
mxirc_dcc $idx "I know about [llength $qlist] normal and [llength $userqlist] user questions.  Question number is $qnumber."
mxirc_dcc $idx "There are [llength [array names userlist]] known people, winscore is $quizconf(winscore)."
mxirc_dcc $idx "Game row restriction: $quizconf(lastwinner_restriction), row length: $quizconf(lastwinner_max_games)"
return 1
}


## exit -- finish da thing and logoff
proc moxquiz_exit {handle idx arg} {
global rankfile uptime botnick statsfilefd
global quizconf
mx_log "--- EXIT requested."
mxirc_say $quizconf(quizchannel) [mc "%sI am leaving now, after running for %s." "[banner] [botcolor boldtxt]" [mx_duration $uptime]]
if {$arg != ""} {
mxirc_say $quizconf(quizchannel) "[bannerspace] $arg"
}
# moxquiz_quizleave $handle $idx $arg
moxquiz_rank_save $handle $idx {}
moxquiz_saveuserquests $handle $idx "all"
moxquiz_config_save $handle $idx {}
if {$statsfilefd != "closed"} { close $statsfilefd }
mxirc_dcc $idx "$botnick now exits."
mx_log "--- $botnick exited"
mx_log "**********************************************************************"

utimer 10 die
}

## aftergame -- what to do if the game is over (won or desert detection)
proc moxquiz_aftergame {handle idx arg} {
global aftergame quizstate

variable thisnext "this"

if {$quizstate == "stopped" || $quizstate == "halted"} {
set thisnext "next"
}

if {$arg == ""} {
mxirc_dcc $idx "After $thisnext game I am planning to: "$aftergame"."
mxirc_dcc $idx "Possible values are: exit, halt, stop, newgame."
} else {
switch -regexp $arg {
"(exit|halt|stop|newgame)" {
set aftergame $arg
mxirc_dcc $idx "After $thisnext game I now will: "$aftergame"."
}
default {
mxirc_dcc $idx "Invalid action.  Chosse from: exit, halt, stop and newgame."
}
}
}
return 1
}

####################
# bot control stuff
####################

## echo a text send by /msg
proc moxquiz_say {handle idx arg} {
global funstuff_enabled botnick
global quizconf

variable channel

set arg [string trim $arg]
if {[regexp -nocase "^(#[^ ]+)( +.*)?" $arg foo channel arg]} {
## check if on channel $channel
if {[validchan $channel] && ![botonchan $channel]} {
mxirc_dcc $idx "Sorry, I'm not on channel "$channel"."
return
}
} else {
set channel $quizconf(quizchannel)
}
set arg [string trim $arg]

mxirc_say $channel "$arg"
variable unused "" cmd "" rest ""

# if it was a fun command, execute it with some delay
if {$funstuff_enabled &&
[regexp "^(![^ ]+)(( *)(.*))?" $arg unused cmd waste spaces rest] &&
[llength [bind pub - $cmd]] != 0} {
if {$rest == ""} {
set rest "{}"
} else {
set rest "{$rest}"
}
eval "[bind pub - $cmd] {$botnick} {} {} {$channel} $rest"
}
}


## say something on al channels
proc moxquiz_say_everywhere {handle idx arg} {
if {$arg != ""} {
mxirc_say_everywhere $arg
} else {
mxirc_dcc $idx "What shall I say on every channel?"
}
}


## act as sent by /msg
proc moxquiz_action {handle idx arg} {
global quizconf
variable channel

set arg [string trim $arg]
if {[regexp -nocase "^(#[^ ]+)( +.*)?" $arg foo channel arg]} {
## check if on channel $channel
if {[validchan $channel] && ![botonchan $channel]} {
mxirc_dc $idx "Sorry, I'm not on channel "$channel"."
return
}
} else {
set channel $quizconf(quizchannel)
}
set arg [string trim $arg]

mxirc_action $channel "$arg"
}


## say something on al channels
proc moxquiz_action_everywhere {handle idx arg} {
if {$arg != ""} {
mxirc_action_everywhere $arg
} else {
mxirc_dcc $idx "What shall act like on every channel?"
}
}


## hop to another channel
proc moxquiz_join {handle idx arg} {
global quizconf
if {[regexp -nocase "^(#[^ ]+)( +.*)?" $arg foo channel arg]} {
set channel [string tolower $channel]
if {[validchan $channel] && [botonchan $channel]} {
set txt "I am already on $channel."
if {$channel == $quizconf(quizchannel)} {
set txt "$txt  It's the quizchannel."
}
mxirc_dcc $idx $txt
} else {
channel add $channel
channel set $channel -inactive
mxirc_dcc $idx "Joined channel $channel."
}
} else {
mxirc_dcc $idx "Please specify channel I shall join. "$arg" not recognized."
}
}


## part an channel
proc moxquiz_part {handle idx arg} {
global quizconf
if {[regexp -nocase "^(#[^ ]+)( +.*)?" $arg foo channel arg]} {
set channel [string tolower $channel]
if {[validchan $channel]} {
if {$channel == $quizconf(quizchannel)} {
mxirc_dcc $idx "Cannot leave quizchannel via part.  User !quizleave or !quizto to do this."
} else {
channel set $channel +inactive
mxirc_dcc $idx "Left channel $channel."
}
} else {
mxirc_dcc $idx "I am not on $channel."
}
} else {
mxirc_dcc $idx "Please specify channel I shall part. "$arg" not recognized."
}
}

## quiz to another channel
proc moxquiz_quizto {handle idx arg} {
global quizconf
if {[regexp "^#.*" $arg] == 0} {
mxirc_dcc $idx "$arg not a valid channel."
} else {
if {$quizconf(quizchannel) != ""} {
# channel set $quizconf(quizchannel) +inactive
mxirc_say $quizconf(quizchannel) [mc "Quiz is leaving to %s.  Goodbye!" $arg]
}
set quizconf(quizchannel) [string tolower $arg]
channel add $quizconf(quizchannel)
channel set $quizconf(quizchannel) -inactive
mxirc_say $quizconf(quizchannel) [mc "Quiz is now on this channel.  Hello!"]
mxirc_dcc $idx "quiz to channel $quizconf(quizchannel)."
mx_log "--- quizto channel $quizconf(quizchannel)"
}
return 1
}


## quiz leave a channel
proc moxquiz_quizleave {handle idx arg} {
global quizconf banner
if {$arg == ""} {
mxirc_say $quizconf(quizchannel) [mc "%s Goodbye." [banner]]
} else {
mxirc_say $quizconf(quizchannel) "[banner] $arg"
}
if {$quizconf(quizchannel) != ""} {
channel set $quizconf(quizchannel) +inactive
mx_log "--- quizleave channel $quizconf(quizchannel)"
mxirc_dcc $idx "quiz left channel $quizconf(quizchannel)"
set quizconf(quizchannel) ""
} else {
mxirc_dcc $idx "I'm not quizzing on any channel."
}
return 1
}


###########################################################################
#
# commands for the questions
#
###########################################################################

## something was said. Solution?
proc moxquiz_pubm {nick host handle channel text} {
global quizstate banner bannerspace
global timeasked theq aftergame
global usergame revoltlist
global lastsolver lastsolvercount
global lastwinner lastwinnercount
global botnick bestscore
global userlist channeltips prices
global quizconf

variable bestscore 0 lastbestscore 0 lastbest ""
variable userarray
variable authorsolved 0 waitforrank 0 gameend 0

## only accept chatter on quizchannel
if {![mx_str_ieq $channel $quizconf(quizchannel)]} {
return
}

## record that the $nick spoke and create entries for unknown people
mx_getcreate_userentry $nick $host
array set userarray $userlist($nick)
set hostmask $userarray(mask)

## not in asking state?
if {$quizstate != "asked"} {
return
}

# nick has revolted
#if {[lsearch -exact $revoltlist $hostmask] != -1} {
#	return
#}

# tweak umlauts in input
set text [mx_tweak_umlauts $text]


global answerarray
set regohneleerzeichen $theq(Regexp)
regsub -all " " $regohneleerzeichen "" regohneleerzeichen

if {[regexp -nocase -- $theq(Regexp) $text] || [regexp -nocase -- $regohneleerzeichen $text]} {


foreach name [array names answerarray] {
unset answerarray($name)
}


## ignore games_max in a row winner
if {[mx_str_ieq [maskhost $host] $lastwinner]
&& $lastwinnercount >= $quizconf(lastwinner_max_games)
&& $quizconf(lastwinner_restriction) == "yes"} {
mxirc_notc $nick [mc "No, you've won the last %d games." $quizconf(lastwinner_max_games)]
return
}

# nick is author of userquest
#if {([info exists theq(Author)] && [mx_str_ieq $nick $theq(Author)])
#|| ([info exists theq(Hostmask)] && [mx_str_ieq [maskhost $host] $theq(Hostmask)])} {
#    set authorsolved 1
#}

## return if overrunprotection set and limit reached
#if {$quizconf(overrun_protection) == "yes"
#    && $userarray(score) == 0
#    && [mx_users_in_rank] > 2
#    && [mx_overrun_limit_reached]} {
#    # [pending] TRANSLATE!
#    mxirc_notc $nick [mc "Sorry, overrun protection enabled.  Wait till end of game."]
#    return
#}

## reset quiz state related stuff (and save userquestions)
mx_answered
set duration [mx_duration $timeasked]

set recdiff ""

global timetypasked schaetzend allow_rec

if {$schaetzend != "" && $schaetzend > 0} {
set typdur $schaetzend
set schaetzend ""
} else {
set typdur [expr ([clock clicks -milliseconds] - $timetypasked) * 0.001]

if {$typdur < "10.000" &&$allow_rec} {

set record [mx_read_record $text]

if {$record == ""} {
mx_save_record $nick $typdur $text
} else {
set recholder [lindex [split $record] 0]
set rectime [lindex [split $record] 1]

if {$rectime > $typdur} {
mx_save_record $nick $typdur $text
}

set recdiff [expr $typdur - $rectime]
if {$recdiff > 0} {set recdiff "+${recdiff}"} else {set recdiff " 02$recdiff 02"}
set recdiff "(${recdiff} Sek. zu [mx_nickobf $recholder]) "
}
}
}




# if it wasn't the author
if {!$authorsolved} {
## save last top score for the test if reset is near (later below)
set lastbest [lindex [lsort -command mx_sortrank [array names userlist]] 0]
if {$lastbest == ""} {
set lastbestscore 0
} else {
array set aa $userlist($lastbest)
set lastbestscore $aa(score)
}

## record nick for bonus points
if {[mx_str_ieq [maskhost $host] $lastsolver]} {
incr lastsolvercount
} else {
set lastsolver [maskhost $host]
set lastsolvercount 1
}

## save score (set started time to time of first point)
incr userarray(score) $theq(Score)
if {$userarray(score) == 1} {
set userarray(started) [unixtime]
}
set userlist($nick) [array get userarray]

## tell channel, that the question is solved
mx_log "--- solved after $duration by $nick with "$text", now $userarray(score) points"


set daten [mx_incr_qnr]



global vokspamvar hintmax hintlist
set vokspamvar 0
set hintmax 0
set hintlist ""


mx_statslog "solved" [list [unixtime] $nick $duration $userarray(score) $theq(Score)]

#mxirc_say $channel [mc "%s solved after %s and now has %s<%d>%s points (+%d) on rank %d." "[banner] [botcolor nick]$nick[botcolor txt]" $duration [botcolor nick] $userarray(score) [botcolor txt] $theq(Score) [mx_get_rank_pos $nick]]

set answrnr [mx_answ_user $nick 1]
set total [regexp -all -nocase {[A-Z]|[0-9]|[ ]} $text]

#bugfix:
if {$typdur <= 0 || $typdur == ""} { set typdur $duration }

set speed [expr $total / $typdur * 60]

mxirc_rsay $channel [mc "%s löst nach %s Sek. ${recdiff}seine %d. Frage und hat %s<%d>%s Punkte (+%d), Platz 9,1~%d~1,11.%s %sA/M: %3.0f" "[banner] [botcolor nick]$nick[botcolor txt]" $typdur $answrnr [botcolor nick] $userarray(score) [botcolor txt] $theq(Score) [mx_get_rank_pos $nick] [botcolor norm] [botcolor question] $speed]


# remove area of tip generation tags
regsub -all "#([^#]*)#" $theq(Answer) "1" answer


global schaetzwert subexp
if {$schaetzwert != ""} {
set showanswer $answer
set schaetzwert [commas $schaetzwert]

set stotal [regexp -all -nocase {[A-Z]|[0-9]|[ ]} $subexp]

if {$stotal > 4} {
regsub -all $subexp $showanswer [commas $subexp] showanswer
}

set showanswer "$showanswer (Abweichung: ${schaetzwert})"
set schaetzwert ""

} else {
set showanswer $answer
}


mxirc_say $channel [mc "%sThe answer was:%s%s" "[bannerspace] [botcolor txt]" "[botcolor norm] [botcolor answer]" $showanswer]
## honor good games!
if {$lastsolvercount == 3} {
mxirc_say $channel [mc "%sThree in a row!" "[bannerspace] [botcolor txt]"]
mx_log "--- $nick has three in a row."
mx_statslog "tiar" [list [unixtime] $nick 3 0]
} elseif {$lastsolvercount == 5} {
mxirc_say $channel [mc "%sCongratulation, five in a row! You receive an extra point." "[bannerspace] [botcolor txt]"]
mx_log "--- $nick has five in a row.  score++"
mx_statslog "tiar" [list [unixtime] $nick 5 1]
moxquiz_rank_set $botnick 0 "$nick +1"
} elseif {$lastsolvercount == 10} {
mxirc_say $channel [mc "%sTen in a row! This is really rare, so you get 3 extra points." "[bannerspace] [botcolor txt]"]
mx_log "--- $nick has ten in a row.  score += 3"
mx_statslog "tiar" [list [unixtime] $nick 10 3]
moxquiz_rank_set $botnick 0 "$nick +3"
} elseif {$lastsolvercount == 20} {
mxirc_say $channel [mc "%sTwenty in a row! This is extremely rare, so you get 5 extra points." "[bannerspace] [botcolor txt]"]
mx_log "--- $nick has twenty in a row.  score += 5"
mx_statslog "tiar" [list [unixtime] $nick 20 5]
moxquiz_rank_set $botnick 0 "$nick +5"
}

## rankreset, if above winscore
# notify if this comes near
set best [lindex [lsort -command mx_sortrank [array names userlist]] 0]
if {$best == ""} {
set bestscore 0
} else {
array set aa $userlist($best)
set bestscore $aa(score)
}

set waitforrank 0
if {[mx_str_ieq $best $nick] && $bestscore > $lastbestscore} {
array set aa $userlist($best)
# tell the end is near
if {$bestscore >= $quizconf(winscore)} {

mx_web $daten $nick

set price "."

if {$quizconf(prices) == "yes"} {
set price " [lindex $prices [rand [llength $prices]]]"
}

mxirc_say $channel [mc "%s%s reaches %d points and wins%s" "[bannerspace] [botcolor txt]" $nick $quizconf(winscore) $price]
set now [unixtime]
if {[mx_str_ieq [maskhost $host] $lastwinner]} {
incr lastwinnercount
if {$lastwinnercount >= $quizconf(lastwinner_max_games)
&& $quizconf(lastwinner_restriction) == "yes"} {
mxirc_say $channel [mc "%s: since you won %d games in a row, you will be ignored for the next game." $nick $quizconf(lastwinner_max_games)]
}
} else {
set lastwinner [maskhost $host]
set lastwinnercount 1
}
# save $nick in allstars table
mx_saveallstar $now [expr $now - $aa(started)] $bestscore $nick [maskhost $host]
mx_statslog "gamewon" [list $now $nick $bestscore $quizconf(winscore) [expr $now - $aa(started)]]

moxquiz_alltimestars_load $botnick 0 $nick
#mxsave_alltimestars

moxquiz_rank $botnick 0 {}
moxquiz_rank_reset $botnick {} {}
set gameend 1
set waitforrank 15
} elseif {$bestscore == [expr $quizconf(winscore) / 2]} {
mxirc_say $channel [mc "%sHalftime.  Game is won at %d points."
"[bannerspace] [botcolor txt]" $quizconf(winscore)]
} elseif {$bestscore == [expr $quizconf(winscore) - 10]} {
mxirc_say $channel [mc "%s%s has 10 points to go." "[bannerspace] [botcolor txt]" $best]
} elseif {$bestscore == [expr $quizconf(winscore) - 5]} {
mxirc_say $channel [mc "%s%s has 5 points to go." "[bannerspace] [botcolor txt]" $best]
} elseif {$bestscore >= [expr $quizconf(winscore) - 3]} {
mxirc_say $channel [mc "%s%s has %d point(s) to go."
"[bannerspace] [botcolor txt]" $best [expr $quizconf(winscore) - $bestscore]]
}

# show rank at 1/3, 2/3 of and 5 before winscore
set spitrank 1
foreach third [list [expr $quizconf(winscore) / 3] [expr 2 * $quizconf(winscore) / 3] [expr $quizconf(winscore) - 5]] {
if {$lastbestscore < $third && $bestscore >= $third && $spitrank} {
moxquiz_rank $botnick 0 {}
set spitrank 0
set waitforrank 15
}
}

}
} else {
## tell channel, that the question is solved by author
mx_log "--- solved after $duration by $nick with "$text" by author"
mxirc_say $channel [mc "%s solved own question after %s and gets no points, keeping %s<%d>%s points on rank %d."
"[banner] [botcolor nick]$nick[botcolor txt]" $duration [botcolor nick] $userarray(score) [botcolor txt] [mx_get_rank_pos $nick]]
# remove area of tip generation tags
regsub -all "#([^#]*)#" $theq(Answer) "1" answer
mxirc_say $channel [mc "%sThe answer was:%s%s" "[bannerspace] [botcolor txt]" "[botcolor norm] [botcolor answer]" $answer]
}

## Give some occasional tips
if {$quizconf(channeltips) == "yes" && [rand 30] == 0} {
mxirc_say $channel [mc "%sHint: %s" "[bannerspace] [botcolor txt]" [lindex $channeltips [rand [llength $channeltips]]]]
}

## check if game has ended and react
if {!$gameend || $aftergame == "newgame"} {
# set up ask timer
utimer [expr $waitforrank + $quizconf(askdelay)] mx_timer_ask
} else {
mx_aftergameaction
}
} elseif {[info exists theq(Category)]} {

if {$theq(Category) == "Schätzfragen"} {


set text [lindex [split $text] 0]

if {![regexp "[0-9]+" $text]} { return }
if {[regexp "[A-Z]" $text]} { return }
if {[regexp "[a-z]" $text]} { return }

if {[regexp -all -nocase {[A-Z]|[0-9]|[ ]} $text] > 12} {}


global schaetzarray timetypasked subexp
regsub -all [{',.!}] $subexp "" subexp

set entry schaetzarray($nick)

set text [expr $text - $subexp]

if {$text < 0} {
set text [expr $text * -1]
}


set typdur [expr ([clock clicks -milliseconds] - $timetypasked) * 0.001]
set schaetzarray($nick) [list $text $typdur]
}

} else {



if {$text==""||$text==" "} { return }

if {[info exists answerarray($nick)]} {

set textzwei [lindex $answerarray($nick) 1]


if {$textzwei==$text||$textzwei=="$text "} { return }


regsub "{" $textzwei "" textzwei
regsub "}" $textzwei "" textzwei

regsub " " $textzwei "" textzwei


if {$textzwei==$text||$textzwei=="$text "} { return }

set textzwei "$textzwei $text"
regsub "{" $textzwei "" textzwei
regsub "}" $textzwei "" textzwei

regsub " " $textzwei "" textzwei

set entry $answerarray($nick)
set answerarray($nick) [list
$nick
$textzwei
]

moxquiz_pubm $nick $host $handle $channel $textzwei


} else {
set answerarray($nick) [list
$nick
$text
]
}

}
}


## Tool function to get the question introduction text
proc mx_get_qtext {complete} {
global theq qnum_thisgame timeasked usergame qlist

set qtext [list "Die Frage Nr. %d (aus [commas [llength $qlist]] Fragen) ist"
"The question no. %d is worth %d points"
"The question no. %d by %s is"
"The question no. %d by %s is worth %d points"
"The user question no. %d is"
"The user question no. %d is worth %d points"
"The user question no. %d by %s is"
"The user question no. %d by %s is worth %d points"
"The level %s question no. %d is"
"The level %s question no. %d is worth %d points"
"The level %s question no. %d by %s is"
"The level %s question no. %d by %s is worth %d points"
"The level %s user question no. %d is"
"The level %s user question no. %d is worth %d points"
"The level %s user question no. %d by %s is"
"The level %s user question no. %d by %s is worth %d points" ]


## game runs, tell user the question via msg
set qtextnum 0
set txt [list $qnum_thisgame]

if {[info exists theq(Level)]} {
incr qtextnum 8
set txt [linsert $txt 0 $theq(Level)]
}

if {$usergame == 1} { incr qtextnum 4 }

if {[info exists theq(Author)]} {
incr qtextnum 2
lappend txt [mx_nickobf $theq(Author)]
}

if {$theq(Score) > 1} {
incr qtextnum 1
lappend txt $theq(Score)
}

set txt [linsert $txt 0 mc [lindex $qtext $qtextnum]]
set txt [eval $txt]

if {$complete == "long"} {
set txt [mc "%s, open for %s:" $txt [mx_duration $timeasked]]
if {[info exists theq(Category)]} {
set txt "$txt ($theq(Category))"
}
set txt "$txt $theq(Question)"
} else {
set txt "$txt:"
}


global datadir
set fname "$datadir/qnr.data"

if {[file exists $fname] && [file readable $fname]} {

set fp [open $fname "r"]
set daten [read -nonewline $fp]
close $fp

} else {

set daten 0

global statsfile
set fp [open $statsfile "r"]
set data [read $fp]
close $fp

foreach line [split $data "
"] {

if {[lindex [split $line] 0] == "solved"} {
incr daten
}
}

set file [open $fname w]
puts $file $daten
close $file

}

#return [eval $txt]
set pre "[banner] [botcolor boldtxt]"
return "${pre}($daten.) $txt"
}



## ask a question, start game
proc moxquiz_ask {nick host handle channel arg} {
global qlist quizstate botnick banner bannerspace
global tipno tiplist
global userqnumber usergame userqlist
global timeasked qnumber theq
global qnum_thisgame
global userlist timerankreset
global quizconf schaetztime subexp
variable anum 0
variable txt

## only accept chatter on quizchannel
if {![mx_str_ieq $channel $quizconf(quizchannel)]} {
return
}

switch -exact $quizstate {
"paused" {
mxirc_notc $nick [mc "Game is paused."]
return 1
}
"stopped" {
mxirc_notc $nick [mc "Game is stopped."]
return 1
}
}

## record that $nick spoke (prevents desert detection from stopping,
## when an user joins and starts the game with !ask)
if {![mx_str_ieq $nick $botnick]} {
mx_getcreate_userentry $nick $host
}

## any questions available?
if {[llength $qlist] == 0 && [mx_userquests_available] == 0} {
mxirc_say $channel [mc "%sSorry, my database is empty." "[banner] [botcolor boldtxt]"]
} elseif {$quizstate == "asked"} {
mxirc_notc $nick [mx_get_qtext "long"]
} elseif {$quizstate == "waittoask" && ![mx_str_ieq $nick $botnick]} {
## no, user has to be patient
mxirc_notc $nick [mc "Please stand by, the next question comes in less than %d seconds." $quizconf(askdelay)]
} else {
##
## ok, now lets see, which question to ask (normal or user)
##

## clear old question
foreach k [array names theq] {
unset theq($k)
}

if {[mx_userquests_available]} {
## select a user question
array set theq [lindex $userqlist $userqnumber]
set usergame 1
incr userqnumber
mx_log "--- asking a user question: $theq(Question)"
} else {
variable ok 0

global bestscore

while {!$ok} {

array set theq [lindex $qlist [mx_next_qnumber]]
set usergame 0

# skip question if author is about to win
if {[info exists theq(Author)] && [info exists userlist($theq(Author))]} {
array set auser $userlist($theq(Author))
if {$auser(score) >= [expr $quizconf(winscore) - 5]} {
mx_log "--- skipping question number $qnumber, author is about to win"
} else {
mx_log "--- asking question number $qnumber: $theq(Question)"
set ok 1
}
} else {
mx_log "--- asking question number $qnumber: $theq(Question)"
set ok 1
}


if {[info exists theq(Category)]} {

if {$theq(Category) == "Ratefragen" && $bestscore > 24} {
set ok 0
} elseif {$theq(Category) == "Schätzfragen"} {

if {[mx_quizzer_count] < 3} {
set ok 0
}
}
}

if {!$ok} {
foreach k [array names theq] {
unset theq($k)
}
}
incr qnumber
}
}
incr qnum_thisgame
if {$qnum_thisgame == 1} {
set timerankreset [unixtime]
mx_log "---- it's the no. $qnum_thisgame in this game, rank timer started at: [unixtime]"
mx_statslog "gamestart" [list $timerankreset]
} else {
mx_log "---- it's the no. $qnum_thisgame in this game."
}

if {[info exists theq(Category)]} {
if {$theq(Category) == "Schätzfragen"} {
global schaetzarray
foreach name [array names schaetzarray] {
unset schaetzarray($name)
}
utimer $schaetztime mx_schaetz_end
} elseif {$theq(Category) == "Ratefragen"} {
Rate_Start $nick $host $handle $channel $arg
return
}
}



##
## ok, set some minimal required fields like score, regexp and the tiplist.
##

## set regexp to match
if {![info exists theq(Regexp)]} {
## mask all regexp special chars except "."
set aexp [mx_tweak_umlauts $theq(Answer)]
regsub -all "(+|?|*|^|$|(|)|[|]|||\)" $aexp "\1" aexp
# get #...# area tags for tipgeneration as regexp
regsub -all ".*#([^#]*)#.*" $aexp "1" aexp
set theq(Regexp) $aexp
} else {
set theq(Regexp) [mx_tweak_umlauts $theq(Regexp)]
}


set subexp $theq(Answer)
# protect embedded numbers
if {[regexp "[0-9]+" $theq(Regexp)]} {
set newexp ""
set oldexp $theq(Regexp)
set theq(Oldexp) $oldexp

while {[regexp -indices "([0-9]+)" $oldexp pair]} {
set subexp [string range $oldexp [lindex $pair 0]  [lindex $pair 1]]
set newexp "${newexp}[string range $oldexp -1 [expr [lindex $pair 0] - 1]]"
if {[regexp -- $theq(Regexp) $subexp]} {
set newexp "${newexp}(^|[^0-9])${subexp}($|[^0-9])"
} else {
set newexp "${newexp}${subexp}"
}
set oldexp "[string range $oldexp [expr [lindex $pair 1] + 1] [string length $oldexp]]"
}
set newexp "${newexp}${oldexp}"
set theq(Regexp) $newexp
#mx_log "---- replaced regexp '$theq(Oldexp)' with '$newexp' to protect numbers."
}

## set score
if {![info exists theq(Score)]} {
set theq(Score) 1
}

## obfs question (answer script stopper)
# [pending] done elsewhere
##set theq(Question) [mx_obfs $theq(Question)]

## set category
## set anum [lsearch -exact $alist "Category"]
## if {![info exists theq(Category)} {
##    set theq(Category) "unknown"
##}

## initialize tiplist
set anum 0
set tiplist ""
while {[info exists theq(Tip$anum)]} {
lappend tiplist $theq(Tip$anum)
incr anum
}
# No tips found?  construct standard list
if {$anum == 0} {
set add "·"

# extract area of tip generation tags (side effect sets answer)
if {![regsub -all ".*#([^#]*)#.*" $theq(Answer) "1" answer]} {
set answer $theq(Answer)
}

## use tipcycle from questions or
## generate less tips if all words shorter than $tipcycle
if {[info exists theq(Tipcycle)]} {
set limit $theq(Tipcycle)
} else {
set limit $quizconf(tipcycle)
## check if at least one word long enough
set tmplist [lsort -command mx_cmp_length -decreasing [split $answer " "]]
# not a big word
if {[string length [lindex $tmplist 0]] < $quizconf(tipcycle)} {
set limit [string length [lindex $tmplist 0]]
}
}

for {set anum 0} {$anum < $limit} {incr anum} {
set tiptext ""
set letterno 0
for {set i 0} {$i < [string length $answer]} {incr i} {
if {([expr [expr $letterno - $anum] % $quizconf(tipcycle)] == 0) ||
([regexp "[- .,`'"]" [string range $answer $i $i] foo])} {
set tiptext "$tiptext[string range $answer $i $i]"
if {[regexp "[- .,`'"]" [string range $answer $i $i] foo]} {
set letterno -1
}
} else {
set tiptext "$tiptext$add"
}
incr letterno
}
lappend tiplist $tiptext
}

# reverse tips for numeric questions
if {[regexp "^[0-9]+$" $answer]} {
set foo ""
for {set i [expr [llength $tiplist] - 1]} {$i >= 0} {set i [expr $i - 1]} {
lappend foo [lindex $tiplist $i]
}
set tiplist $foo
}
}

##
## Now print question header and question
##

mxirc_serv $channel [mx_get_qtext "short"]

set txt "[bannerspace] [botcolor question]"
if {[info exists theq(Category)]} {
set txt "$txt($theq(Category)) $theq(Question)"

if {[info exists theq(Category)]} {
if {$theq(Category) == "Schätzfragen"} {
set txt "$txt [ 0306Ihr habt 0310 $schaetztime  0306Sekunden, um eine Schätzung in arabischen Zahlen abzugeben.] 03"
}
}

} else {
set txt "$txt$theq(Question)"
}

mxirc_serv $channel $txt

set quizstate "asked"
set tipno 0
set timeasked [unixtime]
global timetypasked
set timetypasked [clock clicks -milliseconds]
## set up tip timer
utimer $quizconf(tipdelay) mx_timer_tip
}
}





proc mx_quizzer_count {} {
global quizconf userlist

set qnow [unixtime]
set usermax 0

foreach u [lsort -command mx_sortrank [array names userlist]] {

array set aa $userlist($u)
if {[expr $qnow - $aa(lastspoken)] <= $quizconf(useractivetime)} {
incr usermax
}
}
return $usermax
}



## A user dislikes the question
proc moxquiz_user_revolt {nick host handle channel text} {
global revoltlist revoltmax tipno botnick quizstate
global userlist RateRunning raterevolt
global quizconf

## only accept revolts on the quizchannel
if {![mx_str_ieq $channel $quizconf(quizchannel)]} {
return
}

if {$quizstate == "asked" || $RateRunning == 1} {
if {$tipno < 1&&$RateRunning!=1} {
mxirc_action $channel [mc "does not react on revolts before at least one tip was given."]
return
}

## ensure that the revolting user has an entry
if {![info exists userlist($nick)]} {
mx_getcreate_userentry $nick $host
}

## calculate people needed to make a revolution (50% of active users)
mx_log "--- a game runs, !revolt.  revoltmax = $revoltmax"
if {$revoltmax == 0} {
set now [unixtime]
foreach u [array names userlist] {
array set afoo $userlist($u)
if {[expr $now - $afoo(lastspoken)] <= $quizconf(useractivetime)} {
incr revoltmax
}
}
mx_log "---- active people are $revoltmax"
# one and two player shoud revolt "both"
if {$revoltmax > 2} {
set revoltmax [expr int(ceil(double($revoltmax) / 2))]
}
mx_log "---- people needed for a successful revolution: $revoltmax"
}

# records known users dislike
if {[info exists userlist($nick)]} {
array set anarray $userlist($nick)
set hostmask $anarray(mask)
if {[lsearch -exact $revoltlist $hostmask] == -1} {
#mxirc_quick_notc $nick [mc "Since you are revolting, you will be ignored for this question."]

if {[llength $revoltlist] < $revoltmax && $revoltmax > 0} {
mxirc_quick_action $channel [mc "sees that %s and %d other dislike the question, you need %d people."
$nick [llength $revoltlist] $revoltmax]
}
lappend revoltlist $hostmask
set anarray(lastspoken) [unixtime]
set userlist($nick) [array get anarray]
mx_log "--- $nick is revolting, revoltmax is $revoltmax"
mx_statslog "revolt" [list [unixtime] $nick [llength $revoltlist] $revoltmax]
}
}
if {[llength $revoltlist] >= $revoltmax} {
set revoltmax 0
mx_log "--- solution forced by revolting."
mx_statslog "revoltsolve" [list [unixtime] $revoltmax]
#mxirc_action $channel [mc "will solve the question immediately."]

if {$RateRunning != 0} {

foreach t [utimers] {
set tname [lindex $t 1]

if {[lindex $t 1] == "RateTimeUp"||[lindex $t 1] == "RateDisplayRemainingTime"||[lindex $t 1] == "Rate_ShowResults"||[regexp $tname "Rate"]} {
killutimer [lindex $t 2]
}
}

RateTimesUp
set revoltlist ""
set revoltmax 0
set vokspamvar 0
set raterevolt 1
} else {
moxquiz_solve $botnick 0 {}
}
}
}
}


## solve question
proc moxquiz_solve {handle idx arg} {
global quizstate theq banner bannerspace
global botnick lastsolvercount lastsolver timeasked
global quizconf

variable txt
variable answer
if {$quizstate != "asked"} {
mxirc_dcc $idx "There is no open question."
} else {
mx_answered
set lastsolver ""
set lastsolvercount 0

if {[mx_str_ieq $botnick $handle]} {
set txt [mc "%sAutomatically solved after %s."
"[banner] [botcolor boldtxt]" [mx_duration $timeasked]]
} else {
set txt [mc "%sManually solved after %s by %s"
&quo

source

iChat to Adium Chat Transcript Converter

<?php

// This is the most inefficient piece of shit you will ever see

require_once('Date.php');

$base = getcwd();
$infile = $base . '/iChat Export.txt';
$outdir = $base . '/Converted Transcripts';
$myscreenname = 'theshane100';
$myname = 'Shaun Chapman';
$abort = false;

// Create the output directory if it doesn't exist
if (!file_exists($outdir)) {
mkdir($outdir);
}

$file = file_get_contents($infile);
$lines = explode("
", $file);

$last_alias = '';

foreach ($lines as $line) {
$pieces = explode("	", $line);
$count = count($pieces);
$valid = false;

if ($count == 5) {
$valid = true;
} elseif ($count == 4) {
// Likely a return
$pieces[4] = "
";
$valid = true;
}

if ($valid) {
$alias = $pieces[0];
$info['sender'] = $pieces[1];
$info['time'] = date('Y-m-d', strtotime($pieces[2])) . "T{$pieces[3]}-05:00";
$info['message'] = $pieces[4];

if ($info['sender'] == $myscreenname) {
$info['alias'] = $myname;
} else {
$info['alias'] = $alias;
}

$alias_arr[$alias][] = $info;
}
}


// Build the dictionary
foreach ($alias_arr as $messages) {
foreach ($messages as $message) {
if (!isset($dictionary[$message['alias']])) {
$dictionary[$message['alias']] = $message['sender'];
} elseif ($dictionary[$message['alias']] != $message['sender']) {
echo "Warning:  {$message['alias']} matches with both {$dictionary[$message['alias']]} and {$message['sender']}.
";
//$abort = true;
}
}
}

if ($abort) {
echo "Aborting...
";
exit;
}

// This takes a long time
foreach ($alias_arr as $alias => $messages) {
$last_time = new Date();
$log_num = 0;

foreach ($messages as $message) {
$this_time = new Date($message['time']);
$span = new Date_Span();
$span->setFromDateDiff($last_time, $this_time);

if ((int)$span->toHours() >= 1) {
$last_time = $this_time;
$log_num++;
}

$log_arr[$alias][$log_num][] = $message;
}
}


// Write matched files
foreach ($log_arr as $alias => $logs) {
$matched_folder = "$outdir/Matched";
$not_matched_folder = "$outdir/Not Matched";

if (!file_exists($matched_folder))
mkdir($matched_folder);

if (!file_exists($not_matched_folder))
mkdir($not_matched_folder);

foreach ($logs as $log) {
// Find the other screenname
$screenname = $myscreenname;

foreach ($log as $message) {
if ($message['sender'] != $myscreenname) {
$screenname = $message['sender'];
}
}

if ($screenname != $myscreenname) {
$sn_folder = "$matched_folder/$screenname";
} else {
// Try to match the screenname
if (!empty($dictionary[$alias])) {
$screenname = $dictionary[$alias];
echo "Matched $alias to $screenname.
";
$sn_folder = "$matched_folder/{$dictionary[$alias]}";
} else {
$screenname = '[Unknown]';
echo "Could not find match for $alias.
";
$sn_folder = "$not_matched_folder/$alias";
}
}

if (!file_exists($sn_folder)) {
mkdir($sn_folder);
}

$start_time = $log[0]['time'];
$end_time = $log[count($log) - 1]['time'];
$log_folder = "$sn_folder/$screenname (" . str_replace(':', '.', str_replace('-05:00', '-0500', $start_time)) . ").chatlog";
$log_file = "$log_folder/$screenname (" . str_replace(':', '.', str_replace('-05:00', '-0500', $start_time)) . ").xml";
$output = '';

// Create log folder if it doesn't exist
if (!file_exists($log_folder)) {
mkdir($log_folder);
}

$output .= '<?xml version="1.0" encoding="UTF-8" ?>' . "
";
$output .= "<!-- Converted from iChat Transcript -->
";
$output .= '<chat xmlns="http://purl.org/net/ulf/ns/0.4-02" account="' . $myscreenname . '" service="AIM">';
$output .= '<event type="windowOpened" sender="' . $myscreenname . '" time="' . $start_time . '"/>' . "
";

foreach ($log as $message) {
$output .= '<message sender="' . $message['sender'] . '" time="' . $message['time'] . '" alias="' . $message['alias'] . '">';
$output .= '<div><span style="font-family: Helvetica; font-size: 12pt;">';
$output .= str_replace("
", '', nl2br(htmlspecialchars($message['message'])));
$output .= '</span></div></message>' . "
";
}

$output .= '<event type="windowClosed" sender="' . $myscreenname . '" time="' . $end_time . '"/>' . "
";
$output .= "</chat>
";

// Write to file
file_put_contents($log_file, $output);
}
}

?>

source

Growl support for Aquamacs Emacs

;; Growl support
;;; Requires growlnotify, source for which is included in the Growl disk image
;;; Note that the growlnotify --image option is not reliable on OSX 10.5
;;; see <a href="http://forums.cocoaforge.com/viewtopic.php?f=6&t=17526&p=114069" >http://forums.cocoaforge.com/viewtopic.php?f=6&t=17526&p=114069</a>

;;; Wrapper for growlnotify
(defun growl-chat (title message &optional sticky)
(interactive "sTitle:
sGrowl: ")
(shell-command
(format "/usr/local/bin/growlnotify %s -m '%s' --appIcon 'Aquamacs Emacs' %s" title message (if sticky "--sticky" ""))))

;;; Sticky notifications
(defun growl-chat-sticky (title message)
(interactive "sTitle:
sGrowl: ")
(growl-chat title message t))

;;; Growl nicknames and highlight words when they are mentioned
;;;; Nickname notifications are sticky
(add-hook 'erc-text-matched-hook
(lambda (match-type nickuserhost message)
(when (and
(boundp 'nick)
(not (string= nick "ChanServ"))
(not (string= nick "services.")))
(cond
((eq match-type 'current-nick)
(growl-chat-sticky (format "%s said %s" nick (erc-current-nick)) message))
((eq match-type 'keyword)
(growl-chat (format "%s mentioned a Keyword" nick) message))))))

source

facebook chat

require 'mechanize'
require 'json'
require 'ostruct'
require 'pp'

class FacebookChat
def initialize(email, pass); @email, @pass = email, pass; end

def login
@agent = WWW::Mechanize.new
@agent.user_agent_alias = 'Windows IE 7'
f = @agent.get("http://facebook.com/login.php").forms.first
f.fields.name("email").value = @email
f.fields.name("pass").value = @pass
f.submit
body = @agent.get("http://www.facebook.com/home.php").body

# parse info out of facebook home page
@uid = %r{<a href=".+?/profile.php?id=(d+)" class="profile_nav_link">Profile</a>}.match(body)[1].to_i
@channel = %r{"channel(d+)"}.match(body)[1]
@post_form_id = %r{<input type="hidden" id="post_form_id" name="post_form_id" value="([^"]+)}.match(body)[1]
end

def wait_for_messages
determine_initial_seq_number  unless @seq

begin
json = parse_json @agent.get(get_message_url(@seq)).body
end  while json["t"] == "continue"   # no messages yet, keep waiting
@seq += 1

json["ms"].select{|m| m['type'] == 'msg'}.map do |msg|
info = msg.delete 'msg'
msg['text'] = info['text']
msg['time'] = Time.at(info['time']/1000)
OpenStruct.new msg
end.reject {|msg| msg.from == @uid }  # get rid of messages from us
end

def send_message(uid, text)
r = @agent.post "http://www.facebook.com/ajax/chat/send.php",
:msg_text => text,
:msg_id => rand(999999999),
:client_time => (Time.now.to_f*1000).to_i,
:to => uid,
:post_form_id => @post_form_id
end

def buddy_list
json = parse_json(@agent.post("http://www.facebook.com/ajax/presence/update.php",
:buddy_list => 1, :post_form_id => @post_form_id, :user => @uid).body)
json['payload']['buddy_list']['userInfos'].inject({}) do |hash, (uid, info)|
hash.merge uid => info['name']
end
end

private

def determine_initial_seq_number
# -1 will always be a bad seq number so fb will tell us what the correct one is
json = parse_json @agent.get(get_message_url(-1)).body
@seq = json["seq"].to_i
end

def get_message_url(seq)
"http://0.channel#{@channel}.facebook.com/x/0/false/p_#{@uid}=#{seq}"
end

# get rid of initial js junk, like 'for(;;);'
def parse_json(s)
JSON.parse s.sub(/^[^{]+/, '')
end
end

if __FILE__ == $0
fb = FacebookChat.new(ARGV.shift, ARGV.shift)
fb.login

puts "Buddy List:"
pp fb.buddy_list

Thread.abort_on_exception = true
Thread.new do
puts usage = "Enter message as <facebook_id> <message> (eg: 124423 hey man wassup?) or type 'buddy' for buddy list"
loop do
case gets.strip
when 'buddy' then pp fb.buddy_list
when /^(d+) (.+)$/
uid, text = $1.to_i, $2
fb.send_message(uid, text)
else
puts usage
end
end
end

# message receiving loop
loop do
fb.wait_for_messages.each do |msg|
puts "[#{msg.time.strftime('%H:%M')}] #{msg.from_name} (#{msg.from}): #{msg.text}"
end
end
end

source

chat]

import socket

HOST = '127.0.0.1'# Nome simbolico che rappresenta il nodo locale
PORT = 90007 # Porta non privilegiata arbitraria
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(6)

while 1:
conn, addr = s.accept()
data = conn.recv(1024)
if data=='/quit':
print '...FINE CONNESSIONE CON',addr,'...'
conn.close()
if not data: break
print 'Client',addr,'::. 	'+data
risp=raw_input('Server::. 	')
conn.send(risp)
conn.close()

source

chat]

# -*- coding: UTF-8 -*-
import socket

def risp():
HOST = '127.0.0.1'
PORT = 90007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
text=raw_input('Client::. 	')
if text=='/quit':
print 'BYE'
s.close()
else:
s.send(text)
data = s.recv(1024)
print 'Server::. 	', `data`
s.close()
risp()

risp()

source

How to join a channel (irc network)

/join #channelname

source