root/TriviaEngine/TriviaEngine.tcl

Revision 5, 32.5 KB (checked in by cow, 4 years ago)

fix missing variable

Line 
1# The trivia engine YAY
2# vim: foldmethod=marker:foldcolumn=2:foldmarker=<<<,>>>:sw=2:ts=2
3
4### INIT <<<
5# load mysqltcl
6package require mysqltcl
7
8# the channel to play in
9set trivia_channel "#triviacow"
10
11# the time between hints (sec)
12set trivia_speed 20
13
14# the time between rounds (sec)
15set trivia_delay 30
16
17# hold the current question info <<<
18set trivia_q_id ""
19set trivia_q_cat ""
20set trivia_q_question ""
21set trivia_q_answer ""
22set trivia_q_hint ""
23set trivia_q_attempts 0
24set trivia_unanswered 0
25set trivia_run_last 0
26set trivia_run_qty 0
27set trivia_run_nick ""
28set trivia_guesser ""
29set trivia_guesser_count 0
30set trivia_last_qid 0
31
32if [info exists trivia_must_rehash] {
33  if {$trivia_must_rehash == 1} {
34          set trivia_must_rehash 2
35        } else {
36          set trivia_must_rehash 0
37        }
38} else {
39        set trivia_must_rehash 0
40}
41#>>>
42
43# 0 = off
44# 1 = on
45# -1 = disabled
46set trivia_status 0
47
48set trivia_timer ""
49set trivia_watchdog_timer ""
50set trivia_last_ts 0
51
52#colours <<<
53set trivia_c(off) "\003"
54set trivia_c(red) "\0034"
55set trivia_c(blue) "\0033"
56set trivia_c(purple) "\0036"
57set trivia_c(bold) "\002"
58#>>>
59
60bind pubm - * trivia_input
61bind msg - trivia trivia_msg
62
63# connect mysql <<<
64proc trivia_connect { } {
65        global trivia_db_handle
66        set trivia_db_handle [mysqlconnect -host localhost -user root -password 7MKh3ako -db trivialive]
67}
68#>>>
69
70#>>>
71
72### SETTINGS <<<
73set trivia_flag T
74set trivia_admin S
75# >>>
76
77
78# Handle a /msg
79proc trivia_msg { nick host handle cmd } {
80        #<<<
81        global trivia_db_handle trivia_last_qid
82        global trivia_q_cat trivia_c
83
84        regsub "(trivia )" $cmd "" cmd
85        putlog "trivia: msg command $cmd from $nick"
86
87        if {($nick == "Greeneyez") || ($nick == "JamesOff")} {
88                if [regexp -nocase "^setcat (.+)" $cmd matches category] {
89
90                        if {$trivia_last_qid == 0} {
91                                puthelp "PRIVMSG $nick :Can't fathom last question, unable to update category"
92                                return
93                        }
94
95                        set orig_cat $category
96                        set category [mysqlescape $category]
97                        set sql "SELECT cat_id FROM categories WHERE cat_name='$category'"
98                        set result [mysqlquery $trivia_db_handle $sql]
99
100                        if {[set row [mysqlnext $result]] != ""} {
101                                set cat_id [lindex $row 0]
102                                mysqlendquery $result
103                                puthelp "PRIVMSG $nick :Moving question $trivia_last_qid to category$trivia_c(purple) $category$trivia_c(off) ($cat_id)"
104                                set sql "UPDATE questions SET cat_id='$cat_id' WHERE question_id='$trivia_last_qid'"
105                                mysqlexec $trivia_db_handle $sql
106                                set trivia_q_cat $orig_cat
107                                return
108                        } else {
109                                puthelp "PRIVMSG $nick :Creating new category$trivia_c(purple) $category"
110                                set sql "INSERT INTO categories VALUES (null, '$category', 1)"
111                                mysqlexec $trivia_db_handle $sql
112                                set cat_id [mysqlinsertid $trivia_db_handle]
113                                puthelp "PRIVMSG $nick :Moving question $trivia_last_qid to category$trivia_c(purple) $category$trivia_c(off) ($cat_id)"
114                                set sql "UPDATE questions SET cat_id='$cat_id' WHERE question_id='$trivia_last_qid'"
115                                mysqlexec $trivia_db_handle $sql
116                                set trivia_q_cat $orig_cat
117                                return
118                        }
119                }
120        }
121}
122#>>>
123
124# Handle input coming from a channel
125proc trivia_input { nick host handle channel arg } {
126#<<<
127        global trivia_channel trivia_status trivia_q_answer
128        global trivia_guesser_count trivia_guesser trivia_c
129
130        if {[string tolower $trivia_channel] != [string tolower $channel]} {
131                return 0
132        }
133
134        if [regexp -nocase "^!t(rivia)? (.+)" $arg matches cmd param] {
135                trivia_command $nick $host $handle $channel $param
136                return 0
137        }
138
139        if [regexp -nocase "^!t(rivia)?$" $arg] {
140                if {$trivia_status == 1} {
141                        puthelp "PRIVMSG $trivia_channel :!trivia ... ?"
142                        return 0
143                } else {
144                        puthelp "PRIGMSG $trivia_channel :Perhaps you want $trivia_c(purple)!trivia start"
145                        return 0
146                }
147        }
148
149        # need to be running below here
150        if {$trivia_status == -1} {
151                return 0
152        }
153
154        if {$trivia_q_answer == ""} {
155                return 0
156        }
157
158        #see if someone else is playing
159        if {($nick == $trivia_guesser) && ($nick != "NoTopic")} {
160                incr trivia_guesser_count
161                putloglev d * "$nick has talked $trivia_guesser_count times in a row..."
162        } else {
163                set trivia_guesser_count 0
164                set trivia_guesser $nick
165        }
166
167        #tidy the string up
168        set arg [string tolower $arg]
169        set arg [string trim $arg]
170        if {$arg == [string tolower $trivia_q_answer]} {
171                trivia_correct $nick
172                return 0
173        }
174
175        #if they didn't get it right, and it's been more than 20 lines, taunt!
176        if {($trivia_guesser_count > 0) && (($trivia_guesser_count % 20)) == 0} {
177                putserv "PRIVMSG $trivia_channel :Playing with yourself, $nick? ;)"
178                putlog "Is $nick playing with themselves?"
179        }
180}
181#>>>
182
183# Someone got it right!
184proc trivia_correct { nick } {
185#<<<
186        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status
187        global trivia_timer trivia_delay trivia_db_handle trivia_unanswered trivia_run_qty trivia_run_last trivia_run_nick trivia_c
188
189        if {$trivia_status != 1} {
190                #something strange going on
191                return 0
192        }
193
194        trivia_killtimer
195        set answer $trivia_q_answer
196        set trivia_q_answer ""
197        set newuser 0
198
199        set uid [trivia_get_uid $nick]
200        if {$uid == 0} {
201                putlog "$nick does not have entry in database... creating"
202                set uid [trivia_create_user $nick]
203                set newuser 1
204        }
205
206        putlog "$nick has uid $uid"
207
208        trivia_incr_score $uid
209
210        putquick "PRIVMSG $trivia_channel :Congratulations $trivia_c(purple)$nick$trivia_c(off)! The answer was$trivia_c(purple) $answer$trivia_c(off)."
211        if {$newuser == 1} {
212          putquick "PRIVMSG $trivia_channel :Welcome to our newest player,  $trivia_c(purple)$nick$trivia_c(off) :)"
213        }       
214        putquick "PRIVMSG $trivia_channel :rank0rs: [trivia_near_five2 $uid]"
215
216        #set score [trivia_get_score $uid]
217        #putserv "PRIVMSG $trivia_channel :$nick now has $score points."
218
219        set trivia_timer [utimer $trivia_delay trivia_start_round]
220        set trivia_unanswered 0
221        if {$trivia_run_last == $uid} {
222                incr trivia_run_qty
223                if {$trivia_run_qty > 2} {
224                        putquick "PRIVMSG $trivia_channel :$nick [trivia_get_run $trivia_run_qty] $trivia_run_qty in a row!"
225                }
226        } else {
227                #end of streak
228                if {$trivia_run_qty > 2} {
229                        putquick "PRIVMSG $trivia_channel :$nick ended $trivia_run_nick's winning spree."
230                }
231                set trivia_run_qty 1
232                set trivia_run_last $uid
233                set trivia_run_nick $nick
234        }
235
236        if {[rand 100] > 95} {
237                putserv "PRIVMSG $trivia_channel :Remember, to report a problem with a question or answer, type $trivia_c(purple)!trivia report <description of problem>"
238        }
239
240
241        trivia_check_rehash
242}
243#>>>
244
245#See if we need to rehash
246proc trivia_check_rehash { } {
247#<<<
248  global trivia_must_rehash trivia_channel trivia_c
249  if {$trivia_must_rehash == 1} {
250    putquick "PRIVMSG $trivia_channel :$trivia_c(red)### Please wait, reloading trivia script ###"
251                trivia_killtimer
252    rehash
253  }
254}
255#>>>
256
257# Turn a winning spree into text
258proc trivia_get_run { row } {
259#<<<
260        switch $row {
261                3 {
262                        return "is on a winning spree!"
263                }
264                5 {
265                        return "is on a rampage!"
266                }
267                6 {
268                        return "is unstoppable!"
269                }
270                8 {
271                        return "is on a Google spree!"
272                }
273                10 {
274                        return "is GODLIKE!"
275                }
276                12 {
277                  return "needs to get out more."
278                }
279        }
280        return "is on a roll ..."
281}
282#>>>
283
284# Get someone's user ID from their nick
285proc trivia_get_uid { nick } {
286#<<<
287        global trivia_db_handle
288
289        putloglev 4 * "trivia_get_uid ($nick)"
290
291        set nick [mysqlescape $nick]
292        set sql "SELECT user_id FROM users WHERE user_name = '$nick'"
293        set result [mysqlquery $trivia_db_handle $sql]
294        #putlog $sql
295
296        if {[set row [mysqlnext $result]] != ""} {
297                set user_id [lindex $row 0]
298                mysqlendquery $result
299                return $user_id
300        } else {
301                return 0
302        }
303}
304#>>>
305
306# Get a period
307proc trivia_get_period { } {
308#<<<
309        return [expr [clock scan "last friday 23:59" -gmt true] + 60]
310}
311#>>>
312
313# Get a score from a UID
314proc trivia_get_score { user_id } {
315#<<<
316        global trivia_db_handle
317
318        putloglev 4 * "trivia_get_score ($user_id)"
319
320        set dt [trivia_get_period]
321
322        set sql "SELECT COUNT(*) AS yarr FROM scores WHERE dt > '$dt' AND user_id='$user_id'"
323
324        set result [mysqlquery $trivia_db_handle $sql]
325
326        if {[set row [mysqlnext $result]] != ""} {
327                set score [lindex $row 0]
328                mysqlendquery $result
329                return $score
330        } else {
331                return 0
332        }
333}
334#>>>
335
336# Turn a timestamp into a date
337proc trivia_ts_to_date { ts } {
338#<<<
339  return [clock format $ts -format "%Y/%m/%d %H:%M"]
340}
341#>>>
342
343# Get someone's userinfo from their UID
344proc trivia_get_userinfo { user_id } {
345#<<<
346        global trivia_db_handle
347
348        putloglev 4 * "trivia_get_userinfo ($user_id)"
349
350        set sql "SELECT user_score, user_last, user_reg FROM users WHERE user_id = '$user_id'"
351        set result [mysqlquery $trivia_db_handle $sql]
352
353        if {[set row [mysqlnext $result]] != ""} {
354                set last [lindex $row 1]
355                set score [trivia_get_score $user_id]
356                if {$last == ""} {
357                  set last "Unknown"
358                } else {
359                        set last [trivia_ts_to_date $last]
360                }
361
362                set reg [lindex $row 2]
363                if {$reg == ""} {
364                        set reg "Unkown"
365                } else {
366                        set reg [trivia_ts_to_date $reg]
367                }
368
369                return "$score|$last|$reg"
370                mysqlendquery $result
371        } else {
372                return "No stats"
373        }
374}
375#>>>
376
377# Get someone's stats from their username
378proc trivia_user_stats { user_name } {
379#<<<
380        global trivia_channel
381
382        set uid [trivia_get_uid $user_name]
383        if {$uid == 0} {
384                putserv "PRIVMSG $trivia_channel :Unknown user '$user_name'"
385                return
386        }
387        set stats [trivia_get_userinfo $uid]
388        if {$stats == "No stats"} {
389                putserv "PRIVMSG $trivia_channel :No stats available."
390                return
391        }
392
393        set stats2 [split $stats "|"]
394        putserv "PRIVMSG $trivia_channel :Trivia stats for $user_name:"
395        putserv "PRIVMSG $trivia_channel :  Current score: [lindex $stats2 0]"
396        putserv "PRIVMSG $trivia_channel :        Ranking: [trivia_get_rank $uid]"
397        putserv "PRIVMSG $trivia_channel :     First seen: [lindex $stats2 2]"
398        putserv "PRIVMSG $trivia_channel :    Last scored: [lindex $stats2 1]"
399}
400#>>>
401
402# Increase a UID's score
403proc trivia_incr_score { id { howmuch 1 } } {
404#<<<
405        global trivia_db_handle
406
407        putloglev 4 * "trivia_incr_score ($id, $howmuch)"
408
409        #set sql "UPDATE users SET user_score = user_score + $howmuch WHERE user_id = '$id'"
410        #mysqlexec $trivia_db_handle $sql
411        set sql "UPDATE users SET user_last = UNIX_TIMESTAMP() WHERE user_id = '$id'"
412        mysqlexec $trivia_db_handle $sql
413        set sql "INSERT INTO scores VALUES ('$id', '[clock seconds]')"
414        mysqlexec $trivia_db_handle $sql
415}
416#>>>
417
418# Create a new user
419proc trivia_create_user { nick } {
420#<<<
421        global trivia_db_handle
422
423        putloglev 4 * "trivia_create_user ($nick)"
424
425        set nick [mysqlescape $nick]
426        set sql "INSERT INTO users VALUES (null, '$nick', '', 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())"
427        mysqlexec $trivia_db_handle $sql
428
429        set uid [mysqlinsertid $trivia_db_handle]
430
431        return $uid
432}
433#>>>
434
435# Handle a !trivia command
436proc trivia_command { nick host handle channel param } {
437#<<<
438        global trivia_channel trivia_status trivia_flag trivia_admin trivia_c
439
440        set arg ""
441        regexp {^([^ ]+)( .+)?$} $param matches cmd arg
442        set param [string tolower $cmd]
443        set arg [string trim $arg]
444
445
446        putloglev d *  "trivia command: $param from: $nick ($arg)"
447
448        if {[matchattr $handle |$trivia_admin $trivia_channel] && ($param != "enable") && ($trivia_status == -1)} {
449                return 0
450        }
451
452        if [regexp -nocase "^(score|place)( .+)?" $param] {
453                putserv "PRIVMSG $trivia_channel :[trivia_score $arg $nick]"
454                if [string match -nocase $nick $arg] {
455                        putserv "PRIVMSG $trivia_channel :(You know putting your own nick is optional, right? :)"
456                }
457                return 0
458        }
459
460        if {$param == "top10"} {
461                putserv "PRIVMSG $trivia_channel :[trivia_get_top10]"
462                return 0
463        }
464
465        if {$param == "info"} {
466                trivia_user_stats $arg
467                return 0
468        }
469
470        if {$param == "start"} {
471                trivia_start
472                return 0
473        }
474
475        if {$param == "report"} {
476                trivia_report $nick $arg
477                return 0
478        }
479
480  if {![matchattr $handle |$trivia_flag $channel]} {
481    putserv "PRIVMSG $nick :use: !trivia \[score|top10|start\]"
482    return 0
483  }
484
485  if {$param == "stop"} {
486    trivia_stop
487    return 0
488  }
489
490
491        if {$param == "skip"} {
492                trivia_skip $nick
493                return 0
494        }
495
496        if {$param == "stats"} {
497                trivia_stats
498                return 0
499        }
500
501        if {![matchattr $handle |$trivia_admin $channel]} {
502                putserv "PRIVMSG $nick :use: !trivia \[score|top10|start|stop|skip|stats\]"
503                return 0
504        }
505
506        if {$param == "disable"} {
507                trivia_disable
508                return 0
509        }
510
511        if {$param == "enable"} {
512                trivia_enable
513                return 0
514        }
515
516        if {$param == "merge"} {
517                trivia_merge $nick $arg
518                #puthelp "PRIGMSG $trivia_channel :Score merging is disabled"
519                return 0
520        }
521
522        if {$param == "rehash"} {
523                trivia_rehash
524                return 0
525        }
526
527        putserv "PRIVMSG $nick :use: !trivia \[start|stop|score|top10|skip|stats|enable|disable|merge\]"
528        return 0
529}
530#>>>
531
532# Rehash
533proc trivia_rehash { } {
534#<<<
535        global trivia_status trivia_channel trivia_must_rehash
536        if {$trivia_must_rehash == 1} {
537                putserv "PRIVMSG $trivia_channel :! Reloading trivia now..."
538                rehash
539                return 0
540        }
541
542        if {$trivia_status != 1} {
543                putserv "PRIVMSG $trivia_channel :! Reloading trivia now..."
544                rehash
545                return 0
546        }
547  set trivia_must_rehash 1
548        putserv "PRIVMSG $trivia_channel :Trivia will reload after current round"
549}
550#>>>
551
552# Disable the script
553proc trivia_disable { } {
554#<<<
555        global trivia_status trivia_channel
556
557        if {$trivia_status == 1} {
558                #stop the current game
559                trivia_stop
560        }
561
562        set trivia_status -1
563        putserv "PRIVMSG $trivia_channel :Trivia disabled."
564        return 0
565}
566#>>>
567
568# Enable the script1
569proc trivia_enable {} {
570#<<<
571        global trivia_status trivia_channel
572
573        set trivia_status 0
574        putserv "PRIVMSG $trivia_channel :Trivia enabled."
575
576        set alive [::mysql::ping $trivia_db_handle]
577        if {$alive == false} {
578                putlog "ERROR: mysql has gone away :("
579                putquick "PRIVMSG $trivia_channel :Warning: Unable to reach database!"
580        }
581        return 0
582}
583#>>>
584
585#Make a hint
586proc trivia_make_hint { hint answer } {
587#<<<
588        set hint [string toupper $hint]
589        set answer [string toupper $answer]
590
591        set answer_words [split $answer { }]
592        set final_hint ""
593
594        #are we making the very first hint?
595        if {$hint == ""} {
596                foreach word $answer_words {
597                        append final_hint [string repeat "_" [string length $word]]
598                        append final_hint " "
599                }
600
601                set final_hint [string trim $final_hint]
602
603                #now put the punctuation in
604                set letters [split $answer {}]
605                set i 0
606                foreach letter $letters {
607                        if {![regexp -nocase {[A-Z0-9 ]} $letter]} {
608                                set final_hint [string replace $final_hint $i $i $letter]
609                        }
610                        incr i
611                }
612                return [string trim $final_hint]
613        }
614
615        # explode the into words
616        set hint_words [split $hint { }]
617
618
619        set i 0
620
621        foreach word $hint_words {
622                set answer_word [lindex $answer_words $i]
623                putloglev 1 * "considering $answer_word ($word)"
624
625                #are we on the first iteration?
626                if [regexp "^_+$" $word] {
627                        #use the first letter
628                        set letters [string length $word]
629
630                        #don't hint for single-letter words
631                        if {$letters > 1} {
632                                set word [string index $answer_word 0]
633                                append word [string repeat "_" [expr $letters - 1]]
634                        } else {
635                                set word "_"
636                        }
637                        append final_hint "$word "
638                } else {
639                        #not the first iteration so figure out where the gaps are
640                        set gaps [list]
641                        set letters [split $word {}]
642                        set j 0
643                        foreach letter $letters {
644                                if {$letter == "_"} {
645                                        lappend gaps $j
646                                }
647                                incr j
648                        }
649                        if {[llength $gaps] <= 1} {
650                                #eek no letters to replace, or only one gap
651                                putloglev 1 * "  insufficient gaps, using $word"
652                                append final_hint "$word "
653                        } else {
654                                #now we pick a random letter position
655                                set pos [trivia_random_element $gaps]
656                                putloglev 1 * "  filling in $pos"
657                                set word [string replace $word $pos $pos [string index $answer_word $pos]]
658                                putloglev 1 * "  --> $word"
659                                append final_hint "$word "
660                        }
661                }
662                incr i
663        }
664        set final_hint [string trim $final_hint]
665        return $final_hint
666}
667#>>>
668
669# Fetch a question
670proc trivia_get_question { } {
671#<<<
672        global trivia_db_handle trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_channel
673
674        # make sure we're connected
675        set alive [::mysql::ping $trivia_db_handle]
676        if {$alive == false} {
677                putlog "ERROR: mysql has gone away :("
678                putquick "PRIVMSG $trivia_channel :Couldn't reach database to load next question :("
679                return 0
680        }
681
682        set sql "SELECT q.question, q.question_id, q.answer, c.cat_name FROM questions q LEFT JOIN categories c USING (cat_id) WHERE c.cat_enabled=1 ORDER BY count ASC, rand() LIMIT 1"
683        set result [mysqlquery $trivia_db_handle $sql]
684
685        if {[set row [mysqlnext $result]] != ""} {
686                set trivia_q_id [lindex $row 1]
687                set trivia_q_cat [lindex $row 3]
688                set trivia_q_question [lindex $row 0]
689                set trivia_q_answer [string toupper [lindex $row 2]]
690                set trivia_q_hint ""
691                mysqlendquery $result
692        } else {
693                putlog "ERROR: Couldn't fetch a question from the database."
694        }
695
696        #update the times used
697        set trivia_q_id [mysqlescape $trivia_q_id]
698        set sql "UPDATE questions SET count = count + 1 WHERE question_id = '$trivia_q_id'"
699        mysqlexec $trivia_db_handle $sql
700}
701#>>>
702
703# Start a round
704proc trivia_start_round { } {
705#<<<
706        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status trivia_last_qid
707
708        if {$trivia_status != 1} {
709                #we're switched off, abort
710                return 0
711        }
712
713        #init variables
714        set trivia_q_id ""
715        set trivia_q_cat ""
716        set trivia_q_question ""
717        set trivia_q_answer ""
718        set trivia_q_hint ""
719
720        putlog "Fetching next question..."
721
722        trivia_get_question
723
724        if {$trivia_q_id == ""} {
725                putlog "Couldn't init trivia round, aborting."
726                return
727        }
728
729        putlog "Successfully fetched question $trivia_q_id from database"
730        putloglev 4 * "question = $trivia_q_question"
731        putloglev 4 * "answer   = $trivia_q_answer"
732
733        set trivia_q_attempts 1
734
735        set trivia_last_qid $trivia_q_id
736
737        trivia_round
738}
739#>>>
740
741# Run a round
742proc trivia_round { } {
743#<<<
744        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status
745        global trivia_timer trivia_speed trivia_c trivia_last_ts
746
747        if {$trivia_status != 1} {
748                #we're switched off, abort
749                return 0
750        }
751
752        if {$trivia_q_attempts == 5} {
753                trivia_end_round
754                return 0
755        }
756
757        if {$trivia_q_answer == ""} {
758                return 0
759        }
760
761        #update the hint
762        set trivia_q_hint [trivia_make_hint $trivia_q_hint $trivia_q_answer]
763
764        #say our stuff
765        if {$trivia_q_attempts > 1} {
766                set hint " \[[expr $trivia_q_attempts - 1] of 3\]"
767        } else {
768                set hint ""
769        }
770
771        putserv "PRIVMSG $trivia_channel :$trivia_c(red)--== Trivia ==--$trivia_c(off) \[category: \002$trivia_q_cat\002\]"
772        #\[question id: \002$trivia_q_id\002\]"
773        set split_question [trivia_question_split $trivia_q_question]
774        foreach q $split_question {
775                if {$q != ""} {
776                        putserv "PRIVMSG $trivia_channel :$trivia_c(blue) [trivia_question_inject $q]"
777                }
778        }
779        #set new_question [trivia_question_inject $trivia_q_question]
780        #putserv "PRIVMSG $trivia_channel :$trivia_c(blue) $new_question"
781        putserv "PRIVMSG $trivia_channel :Hint$hint: [trivia_explode $trivia_q_hint]"
782
783        incr trivia_q_attempts
784
785        set trivia_last_ts [clock seconds]
786
787        global trivia_must_rehash
788  if {$trivia_must_rehash != 2} {
789                set trivia_timer [utimer $trivia_speed trivia_round]
790        }
791}
792#>>>
793
794# Make it harder for things to break questions (inject bold codes)
795proc trivia_question_inject { question } {
796#<<<
797  putlog "trivia_question_inject $question"
798        #inject random bold/underline/colour codes into question
799        global trivia_c
800
801        set l [string length $question]
802        putlog "length: $l"
803        if {$l < 1} {
804          return $question
805        }
806        set pos [rand $l]
807        set first [string range $question 0 $pos]
808        incr pos
809        set second [string range $question $pos end]
810        switch [rand 1] {
811                0 {
812                        putlog "question_inject: using bold at pos $pos"
813                        return $first$trivia_c(bold)$trivia_c(bold)$second
814                }
815                1 {
816                        putlog "question_inject: using purple at pos $pos"
817                        return $first$trivia_c(purple)$trivia_c(off)$second
818                }
819        }
820        return $question
821}
822#>>>
823
824# Make it harder for things to break questions (inject line breaks)
825proc trivia_question_split { question } {
826#<<<
827  putlog "trivia_question_split $question"
828        #explodes a question into two lines at word boundaries, if it's long enough
829        #don't split unscrambles incorrectly
830        if [regexp -nocase "(unscramble .+:) (\[A-Z \]+)" $question matches first second] {
831                return [list $first $second]
832        }
833        set words [split $question " "]
834        set wordcount [llength $words]
835        if {$wordcount < 4} {
836          putlog "aborting, too short"
837                return [list $question]
838        }
839
840        #enough words to split
841        #we want at least two on the first line
842        putlog "wordcount: $wordcount"
843        incr wordcount -2
844        if {$wordcount < 0} {
845                return [list $question]
846        }
847        set pos [rand $wordcount]
848        incr pos 2
849        putlog "picked pos $pos"
850        set wordlist [list]
851        set i 0
852        set line ""
853        foreach word $words {
854                #putlog "word = $word, i = $i"
855                append line "$word "
856                if {$i == $pos} {
857                        #putlog "splitting here, line = $line"
858                        lappend wordlist [string trim $line]
859                        set line ""
860                }
861                incr i
862        }
863        #putlog "done, appending $line to list"
864        if {$line != ""} {
865                lappend wordlist [string trim $line]
866        }
867        #putlog "split question list is: $wordlist"
868        return $wordlist
869}
870#>>>
871
872# Finish a round (without a winner)
873proc trivia_end_round { } {
874#<<<
875        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status
876        global trivia_timer trivia_delay trivia_db_handle trivia_unanswered
877        global trivia_run_last trivia_run_nick trivia_run_qty trivia_c
878
879        if {$trivia_status != 1} {
880                #we're switched off, abort
881                return 0
882        }
883
884        set trivia_q_answer [string toupper $trivia_q_answer]
885        putquick "PRIVMSG $trivia_channel :Time's up! Nobody got it right. The answer was$trivia_c(purple) $trivia_q_answer"
886        set trivia_q_answer ""
887
888        incr trivia_unanswered
889        if {$trivia_run_qty > 2} {
890                putserv "PRIVMSG $trivia_channel :So much for $trivia_run_nick's winning spree."
891        }
892        set trivia_run_last 0
893        set trivia_run_qty 0
894        set trivia_run_nick ""
895
896        if {[rand 100] > 90} {
897                putserv "PRIVMSG $trivia_channel :Remember, to report a problem with a question or answer, type $trivia_c(purple)!trivia report <description of problem>"
898        }
899
900        if {$trivia_unanswered > 3} {
901                putserv "PRIVMSG $trivia_channel :Three unanswered in a row, stopping the game."
902                set trivia_status 0
903        } else {
904                set trivia_timer [utimer $trivia_delay trivia_start_round]
905                trivia_check_rehash
906        }
907}
908#>>>
909
910# Skip the rest of this question
911proc trivia_skip { nick } {
912#<<<
913        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status
914        global trivia_timer trivia_delay trivia_db_handle trivia_unanswered
915
916        if {$trivia_status != 1} {
917                #we're switched off, abort
918                return 0
919        }
920
921        if {$trivia_q_answer == ""} {
922                #no round in progress
923                return 0
924        }
925
926        set trivia_q_question ""
927        set trivia_q_answer ""
928
929        trivia_killtimer
930
931        putserv "PRIVMSG $trivia_channel :Skipping this question by $nick's request."
932        set trivia_timer [utimer $trivia_delay trivia_start_round]
933}
934#>>>
935
936# Utility function to fetch a random item from a list
937proc trivia_random_element { l } {
938#<<<
939        return [lindex $l [rand [llength $l]]]
940}
941#>>>
942
943# Start the game
944proc trivia_start { } {
945#<<<
946        global trivia_status trivia_channel trivia_unanswered trivia_run_last trivia_run_qty trivia_c trivia_must_rehash trivia_db_handle
947
948        if {$trivia_status == 1} {
949                putserv "PRIVMSG $trivia_channel :Trivia is already running."
950                return 0
951        }
952
953        if {$trivia_status == -1} {
954                putserv "PRIVMSG $trivia_channel :Trivia is currently disabled."
955                return 0
956        }
957
958        set alive [::mysql::ping $trivia_db_handle]
959        if {$alive == false} {
960                putlog "ERROR: mysql has gone away :("
961                putquick "PRIVMSG $trivia_channel :Unable to start game; can't reach database :("
962        }
963
964        # go go go
965        set trivia_status 1
966        if {$trivia_must_rehash == 2 } {
967                putquick "PRIVMSG $trivia_channel :$trivia_c(blue)### Resuming trivia game ###" -next
968        } else {
969                putquick  "PRIVMSG $trivia_channel :Trivia game started!" -next
970        }
971
972        #trivia_stats
973
974        set trivia_unanswered 0
975        set trivia_run_last 0
976        set trivia_run_qty 0
977
978        trivia_start_round
979        return 0
980}
981#>>>
982
983# Stop the game
984proc trivia_stop { } {
985#<<<
986        global trivia_channel trivia_status
987
988        if {$trivia_status == 1} {
989                putserv "PRIVMSG $trivia_channel :Trivia game stopped."
990                set trivia_status 0
991                trivia_killtimer
992        }
993        return 0
994}
995#>>>
996
997# Kill our timer
998proc trivia_killtimer { } {
999#<<<
1000        global trivia_timer
1001
1002        if {$trivia_timer != ""} {
1003                killutimer $trivia_timer
1004        }
1005}
1006#>>>
1007
1008# Utility function to explode line into letters
1009proc trivia_explode { line } {
1010#<<<
1011        set letters [split $line {}]
1012        set newline ""
1013        foreach letter $letters {
1014                append newline "$letter "
1015        }
1016        return [string trim $newline]
1017}
1018#>>>
1019
1020# Get a UID's ranking
1021proc trivia_get_rank { uid } {
1022#<<<
1023        global trivia_db_handle
1024
1025        putloglev 4 * "trivia_get_rank ($uid)"
1026
1027        set sql "SELECT user_id FROM users ORDER by user_score DESC"
1028        set dt [trivia_get_period]
1029        set sql "select user_id, count(dt) as d from scores where dt > $dt group by user_id order by d desc"
1030        set result [mysqlsel $trivia_db_handle $sql -flatlist]
1031
1032        set pos [lsearch -exact $result $uid]
1033        return [expr $pos + 1]
1034}
1035#>>>
1036
1037# Get the top 10 users
1038proc trivia_get_top10 { } {
1039#<<<
1040        global trivia_db_handle
1041
1042        set sql "SELECT user_name, user_score FROM users ORDER BY user_score DESC LIMIT 10"
1043        set dt [trivia_get_period]
1044        set sql "select users.user_name, count(dt) as d from scores left join users using (user_id) where dt > $dt group by scores.user_id order by d desc limit 10"
1045
1046        set result [mysqlsel $trivia_db_handle $sql -list]
1047        set output ""
1048        set index 0
1049
1050        foreach place $result {
1051                incr index
1052                append output "\002$index:\002 "
1053                append output [lindex $place 0]
1054                append output " ("
1055                append output [lindex $place 1]
1056                append output ")  "
1057        }
1058
1059        set output "The top $index players are... $output"
1060        return $output
1061}
1062#>>>
1063
1064# Fix a number into text
1065proc trivia_ordinal { number } {
1066#<<<
1067        if [regexp {1[0-9]$} $number] {
1068                return "th"
1069        }
1070
1071        set last [string range $number end end]
1072
1073        if {$last == "1"} {
1074                return "st"
1075        }
1076
1077        if {$last == "2"} {
1078                return "nd"
1079        }
1080
1081        if {$last == "3"} {
1082                return "rd"
1083        }
1084
1085        return "th"
1086}
1087#>>>
1088
1089# Get a score
1090proc trivia_score { n { nick "" } } {
1091#<<<
1092        set n [string trim $n]
1093        putloglev 4 * "trivia_score($n, $nick)"
1094
1095        if {$n == ""} {
1096                set ni $nick
1097                set o "You are"
1098        } else {
1099                set ni $n
1100                set o "$n is"
1101        }
1102
1103        set uid [trivia_get_uid $ni]
1104        set score [trivia_get_score $uid]
1105        set pos [trivia_get_rank $uid]
1106        if {$score == 0} {
1107                return "No score found for $n."
1108        }
1109        return "$o ranked $pos[trivia_ordinal $pos] with $score points."
1110}
1111#>>>
1112
1113# Get the scores around a UID
1114proc trivia_near_five { uid } {
1115#<<<
1116        global trivia_db_handle trivia_c
1117
1118        set sql "SELECT user_id, user_name, user_score FROM users ORDER BY user_score DESC"
1119        set dt [trivia_get_period]
1120        set sql "select users.user_id, users.user_name, count(dt) as user_score from scores left join users using (user_id) where dt > $dt group by scores.user_id order by user_score desc"
1121
1122        set result [mysqlsel $trivia_db_handle $sql -flatlist]
1123
1124        set pos [lsearch -exact $result $uid]
1125
1126        #we use +- 6 here because it's a flat list, and we want 2 nodes either side
1127        putlog $result
1128        set near_five [lrange $result [expr $pos - 6] [expr $pos + 8]]
1129
1130        putlog $near_five
1131        set low_pos [expr round(($pos-1) / 3)]
1132        if {$low_pos < 1} {
1133                set low_pos 1
1134        }
1135        putlog $low_pos
1136        set i 0
1137        set output ""
1138        while {$i < [llength $near_five]} {
1139                set user_id [lindex $near_five $i]
1140                incr i
1141                set nick [lindex $near_five $i]
1142                incr i
1143                set score [lindex $near_five $i]
1144                incr i
1145
1146                if {$uid == $user_id} {
1147                        append output "$trivia_c(purple)$trivia_c(bold)"
1148                }
1149
1150                append output "$low_pos[trivia_ordinal $low_pos]:"
1151                append output "$nick"
1152                append output " ($score)  "
1153
1154                if {$uid == $user_id} {
1155                        append output "$trivia_c(off)$trivia_c(bold)"
1156                }
1157
1158                incr low_pos
1159        }
1160        return $output
1161}
1162#>>>
1163
1164# Turn a list into a stats list
1165proc trivia_list_to_stats { pos user_id l } {
1166#<<<
1167        putloglev 4 * "trivia_list_to_stats ($pos, $user_id, $l)"
1168        global trivia_c
1169        set uid [lindex $l 0]
1170        set nick [lindex $l 1]
1171        set score [lindex $l 2]
1172        incr pos
1173
1174        set result ""
1175        if {$user_id == $uid} {
1176                set result "$trivia_c(purple)$trivia_c(bold)"
1177        }
1178        append result "$pos[trivia_ordinal $pos]: $nick ($score)  "
1179        if {$user_id == $uid} {
1180                append result "$trivia_c(off)$trivia_c(bold)"
1181        }
1182        return $result
1183}
1184#>>>
1185
1186# Another function to get the nearest users to your score
1187proc trivia_near_five2 { uid } {
1188#<<<
1189        global trivia_db_handle trivia_c
1190
1191        set sql "SELECT user_id, user_name, user_score FROM users ORDER BY user_score DESC"
1192        set dt [trivia_get_period]
1193  set sql "select users.user_id, users.user_name, count(dt) as user_score from scores left join users using (user_id) where dt > $dt group by scores.user_id order by user_score desc"
1194
1195        set result [mysqlsel $trivia_db_handle $sql -list]
1196
1197  putloglev d * "current score list: $result"
1198
1199        set position 0
1200        foreach item $result {
1201                if {[lindex $item 0] == $uid} {
1202                        putloglev d * "found at position $position"
1203                        break
1204                }
1205                incr position
1206        }
1207
1208        set line ""
1209
1210        if {$position > 2} {
1211                append line [trivia_list_to_stats [expr $position - 2] $uid [lindex $result [expr $position - 2]]]
1212        }
1213
1214        if {$position > 1} {
1215                append line [trivia_list_to_stats [expr $position - 1] $uid [lindex $result [expr $position - 1]]]
1216        }
1217
1218        append line [trivia_list_to_stats $position $uid [lindex $result $position]]
1219
1220        if {$position < [expr [llength $result] - 1]} {
1221                append line [trivia_list_to_stats [expr $position + 1] $uid [lindex $result [expr $position + 1]]]
1222        }
1223
1224        if {$position < [expr [llength $result] - 2]} {
1225                append line [trivia_list_to_stats [expr $position + 2] $uid [lindex $result [expr $position + 2]]]
1226        }
1227
1228        return $line
1229}
1230#>>>
1231
1232# Get some stats from the DB
1233proc trivia_stats { } {
1234#<<<
1235        global trivia_db_handle trivia_channel
1236
1237        set sql "SELECT COUNT(*) AS total FROM questions LEFT JOIN categories USING (cat_id) WHERE categories.cat_enabled = 1;"
1238        set result [mysqlsel $trivia_db_handle $sql -flatlist]
1239        set stat_total_questions [lindex $result 0]
1240
1241        set sql "SELECT COUNT(*) AS total FROM categories WHERE cat_enabled = 1"
1242        set result [mysqlsel $trivia_db_handle $sql -flatlist]
1243        set stat_total_cats [lindex $result 0]
1244
1245        putserv "PRIVMSG $trivia_channel :Using\002 $stat_total_questions\002 questions in\002 $stat_total_cats\002 categories."
1246}
1247#>>>
1248
1249# Merge two users
1250proc trivia_merge { nick param } {
1251#<<<
1252        global trivia_db_handle
1253
1254        putloglev 4 * "trivia_merge ($nick, $param)"
1255
1256        if [regexp {^([^ ]+) (.+)$} $param matches nick1 nick2] {
1257                set olduid [trivia_get_uid [mysqlescape $nick1]]
1258                set newuid [trivia_get_uid [mysqlescape $nick2]]
1259
1260                if {$olduid == 0} {
1261                        puthelp "PRIVMSG $nick :Can't find user '$nick1'"
1262                        return 0
1263                }
1264
1265                if {$newuid == 0} {
1266                        puthelp "PRIVMSG $nick :Can't find user '$nick2'"
1267                        return 0
1268                }
1269
1270                puthelp "PRIVMSG $nick :Meging score for $nick1 into score for $nick2"
1271                set sql "UPDATE scores SET user_id=$newuid WHERE user_id=$olduid"
1272                mysqlexec $trivia_db_handle $sql
1273
1274                set newscore [trivia_get_score $newuid]
1275                puthelp "PRIVMSG $nick :$nick2 now has $newscore points."
1276
1277                set sql "DELETE FROM users WHERE user_id = $olduid"
1278                mysqlexec $trivia_db_handle $sql
1279                puthelp "PRIVMSG $nick :User $nick1 has been deleted."
1280                return 0
1281        } else {
1282                puthelp "PRIVMSG $nick :Use: !trivia merge <olduser> <newuser>"
1283                puthelp "PRIVMSG $nick :  olduser's score is merged with newuser's and olduser is deleted."
1284        }
1285}
1286#>>>
1287
1288# Find people who can start the script
1289# TODO: is this still used?
1290proc trivia_find_starters { } {
1291#<<<
1292  global trivia_channel trivia_flag
1293        set nicks [chanlist #triviacow &$trivia_flag]
1294
1295        if {[llength $nicks] > 0} {
1296                return "One of the following users may be able to help: $nicks"
1297        } else {
1298          return "Sorry, noone who can start trivia is present."
1299        }
1300}
1301#>>>
1302
1303# Report a broken question
1304proc trivia_report { nick msg } {
1305#<<<
1306        global trivia_channel trivia_db_handle trivia_last_qid trivia_c
1307
1308        if {$trivia_last_qid == 0} {
1309                puthelp "PRIVMSG $trivia_channel :Sorry, unable to work out which question to report on :("
1310                return 0
1311        }
1312
1313        set nick [mysqlescape $nick]
1314        set msg [mysqlescape $msg]
1315
1316        set sql "INSERT INTO reports VALUES (null, UNIX_TIMESTAMP(), '$nick', '$trivia_last_qid', '$msg', 'N')"
1317        mysqlexec $trivia_db_handle $sql
1318        puthelp "PRIVMSG $trivia_channel :Added a report against question ID$trivia_c(purple) $trivia_last_qid$trivia_c(off) from $trivia_c(purple)$nick$trivia_c(off)."
1319        set trivia_last_qid 0
1320}
1321#>>>
1322
1323### WATCHDOG STUFF <<<
1324# Watchdog timer to make sure we're not ruined
1325proc trivia_watchdog { } {
1326#<<<
1327        global trivia_last_ts trivia_watchdog_timer trivia_status trivia_channel
1328
1329        putloglev d * "trivia watchdog: tick"
1330
1331        if {$trivia_last_ts == 0} {
1332                #never asked a question
1333                set trivia_watchdog_timer [utimer 45 trivia_watchdog]
1334                return 0
1335        }
1336
1337        set current_ts [clock seconds]
1338        set difference [expr $current_ts - $trivia_last_ts]
1339
1340        if {$difference > 60} {
1341                if {$trivia_status == 1} {
1342                        putlog "watchdog: trivia is broken"
1343                        #putserv "PRIVMSG $trivia_channel :Oops, I think I'm broken. Attempting to recover..."
1344                        #set trivia_status 0
1345                        #trivia_start
1346                        putlog "trivia watchdog: current: $current_ts, last: $trivia_last_ts, difference: $difference"
1347                }
1348        }
1349
1350        set trivia_watchdog_timer [utimer 10 trivia_watchdog]
1351        return 0
1352}
1353#>>>
1354
1355# Kill the watchdog timeer
1356proc trivia_killwatchdog { } {
1357#<<<
1358        global trivia_watchdog_timer
1359
1360        if {$trivia_watchdog_timer != ""} {
1361                killutimer $trivia_watchdog_timer
1362        }
1363}
1364#>>>
1365
1366trivia_killwatchdog
1367set trivia_watchdog_timer [utimer 45 trivia_watchdog]
1368#>>>
1369
1370trivia_connect
1371
1372putlog {TriviaEngine ENGAGED(*&($}
1373
1374if {$trivia_must_rehash == 2} {
1375  putlog "Auto-restarting trivia..."
1376        trivia_start
1377        set trivia_must_rehash 0
1378}
Note: See TracBrowser for help on using the browser.