source: TriviaEngine/TriviaEngine-sqlite.tcl @ 35

Revision 35, 49.0 KB checked in by james, 5 years ago (diff)

tell people when they're quick

Line 
1# The trivia engine YAY
2# vim: foldmethod=marker:foldcolumn=2:foldmarker=<<<,>>>:sw=2:ts=2
3
4### INIT <<<
5package require sqlite
6
7# the channel to play in
8set trivia_channel "#triviacow"
9
10# the time between hints (sec)
11set trivia_speed 20
12
13# the time between rounds (sec)
14set trivia_delay 30
15
16# allow new categories to be created?
17set trivia_allow_new_cats 0
18
19# time before end of round to start counting down
20set trivia_time_left_warning 86400
21
22# hold the current question info <<<
23set trivia_q_id ""
24set trivia_q_cat ""
25set trivia_q_question ""
26set trivia_q_answer ""
27set trivia_q_hint ""
28set trivia_q_attempts 0
29set trivia_unanswered 0
30set trivia_run_last 0
31set trivia_run_qty 0
32set trivia_run_nick ""
33set trivia_guesser ""
34set trivia_guesser_count 0
35set trivia_last_qid 0
36set trivia_q_timestamp 0
37if [info exists trivia_must_rehash] {
38  if {$trivia_must_rehash == 1} {
39          set trivia_must_rehash 2
40        } else {
41          set trivia_must_rehash 0
42        }
43} else {
44        set trivia_must_rehash 0
45}
46#>>>
47
48# 0 = off
49# 1 = on
50# -1 = disabled
51set trivia_status 0
52
53set trivia_timer ""
54set trivia_watchdog_timer ""
55set trivia_last_ts 0
56set trivia_score_time 0
57set trivia_debug_mode 0
58set trivia_warned 0
59set trivia_asking_question 0
60set trivia_current_leader -1
61
62#colours <<<
63set trivia_c(off) "\003"
64set trivia_c(red) "\0034"
65set trivia_c(blue) "\0033"
66set trivia_c(purple) "\0036"
67set trivia_c(bold) "\002"
68set trivia_c(realblue) "\0032"
69#>>>
70
71bind pubm - * trivia_input
72bind msg - trivia trivia_msg
73
74# connect database <<<
75proc trivia_connect { } {
76        global trivia_db_handle
77        sqlite3 trivia_db_handle trivia.db
78}
79#>>>
80
81#>>>
82
83### SETTINGS <<<
84set trivia_flag T
85set trivia_admin S
86
87#botnet handle of the bmotion bot we're going to play with (set blank to disable)
88set trivia_bmotion_bot "NoTopic"
89# >>>
90
91# Send a botnet command to the bmotion bot
92proc trivia_bmotion_send { command params } {
93        global trivia_bmotion_bot
94       
95        if {$trivia_bmotion_bot == ""} {
96                return 0
97        }
98
99        if [islinked $trivia_bmotion_bot] {
100                putbot $trivia_bmotion_bot "trivia $command :$params"
101                putloglev d * "triviaengine: send $command to $trivia_bmotion_bot with params $params"
102        } else {
103                putlog "triviaengine: trying to communicate with bmotion bot $trivia_bmotion_bot but it's not linked"
104        }
105}
106
107
108
109# Handle a /msg
110proc trivia_msg { nick host handle cmd } {
111        #<<<
112        global trivia_db_handle trivia_last_qid
113        global trivia_q_cat trivia_c trivia_allow_new_cats
114
115        regsub "(trivia )" $cmd "" cmd
116        putlog "trivia: msg command $cmd from $nick"
117
118        if {($nick == "Greeneyez") || ($nick == "JamesOff")} {
119#<<< set a question's category
120                if [regexp -nocase "^setcat (.+)" $cmd matches category] {
121
122                        if {$trivia_last_qid == 0} {
123                                puthelp "PRIVMSG $nick :Can't fathom last question, unable to update category"
124                                return
125                        }
126
127                        set orig_cat $category
128                        set category [trivia_sqlite_escape $category]
129                        set sql "SELECT cat_id FROM categories WHERE cat_name='$category'"
130                        set cat_id 0
131                       
132                        set cat_id [trivia_db_handle eval $sql]
133                        if {$cat_id != ""} {
134                                puthelp "PRIVMSG $nick :Moving question $trivia_last_qid to category$trivia_c(purple) $category$trivia_c(off) ($cat_id)"
135                                set sql "UPDATE questions SET cat_id='$cat_id' WHERE question_id='$trivia_last_qid'"
136                                trivia_db_handle eval $sql
137                                set trivia_q_cat $orig_cat
138                                return
139                        } else {
140                                if {$trivia_allow_new_cats == 1} {
141                                        puthelp "PRIVMSG $nick :Creating new category$trivia_c(purple) $category"
142                                                set sql "INSERT INTO categories VALUES (null, '$category', 1)"
143                                                putloglev d * $sql
144                                                trivia_db_handle eval $sql
145                                                set cat_id [trivia_db_handle last_insert_rowid]
146                                                puthelp "PRIVMSG $nick :Moving question $trivia_last_qid to category$trivia_c(purple) $category$trivia_c(off) ($cat_id)"
147                                                set sql "UPDATE questions SET cat_id='$cat_id' WHERE question_id='$trivia_last_qid'"
148                                                putloglev d * $sql
149                                                trivia_db_handle eval $sql
150                                                set trivia_q_cat $orig_cat
151                                } else {
152                                        puthelp "PRIVMSG $nick :Creating new categories is $trivia_c(purple)DISABLED$trivia_c(off). ('trivia newcat enable' to enable.)"
153                                }
154                                return
155                        }
156                }
157#>>>
158
159        #<<< enable or disable new category creation
160        if [regexp -nocase "^newcat (enable|disable)" $cmd matches toggle] {
161                if {$toggle == "enable"} {
162                        puthelp "PRIVMSG $nick :$trivia_c(purple)ENABLING$trivia_c(off) new category creation"
163                        set trivia_allow_new_cats 1
164                        return
165                }
166
167                if {$toggle == "disable"} {
168                        puthelp "PRIVMSG $nick :$trivia_c(purple)DISABLING$trivia_c(off) new category creation"
169                        set trivia_allow_new_cats 0
170                        return
171                }
172
173                puthelp "PRIVMSG $nick :Use: trivia newcat enable|disable"
174                return
175        }
176#>>>
177
178#<<< debug
179                if [regexp -nocase {^debug (.+)} $cmd matches func] {
180                        global trivia_debug_mode
181                       
182                        if {$trivia_debug_mode == 0} {
183                                putquick "PRIVMSG $nick :Debug mode is disabled. Cannot use debug commands."
184                                return 0
185                        }
186
187                        if {$func == "endweek"} {
188                                putquick "PRIVMSG $nick :Ending this week in 10 seconds..."
189                                global trivia_score_time
190                                set trivia_score_time [expr [clock seconds] + 10]
191                                return 0
192                        }
193                }
194#>>>
195
196
197#<<< handle reports
198                if [regexp -nocase {^report (help|list|fix|view|done|delete)?( .+)?} $cmd matches func arg] {
199                        if {($func == "") || ($func == "help")} {
200                                puthelp "PRIVMSG $nick :Use: report (list|view|fix|done|delete)"
201                                puthelp "PRIVMSG $nick :report list: see 10 reports"
202                                puthelp "PRIVMSG $nick :report view <id>: see the question and answer associated with a report"
203                                puthelp "PRIVMSG $nick :report fix <id> (question|answer) <new text>: update a question or answer"
204                                puthelp "PRIVMSG $nick :report done <id>: mark a report as done"
205                                return 0
206                        }
207
208                        if {$func == "list"} {
209                                putserv "PRIVMSG $nick :Gathering 10 trivia reports..."
210                                set sql "SELECT * FROM reports WHERE resolved = 'N' LIMIT 10"
211                                trivia_db_handle eval $sql result {
212                                        putserv "PRIVMSG $nick :$result(report_id): [format %10s $result(who)] $result(message)"
213                                }
214                                return 0
215                        }
216
217                        if {$func == "view"} {
218                                if {$arg == ""} {
219                                        puthelp "PRIVMSG $nick :Use: report view <id>"
220                                        return 0
221                                }
222
223                                set arg [string trim $arg]
224                                set arg [trivia_sqlite_escape $arg]
225                                set sql "SELECT * FROM reports, questions WHERE report_id = '$arg' AND reports.question_id = questions.question_id"
226                                trivia_db_handle eval $sql result {
227                                        putserv "PRIVMSG $nick :Report$trivia_c(purple) $result(report_id) $trivia_c(off)by$trivia_c(purple) $result(who) $trivia_c(off)on$trivia_c(blue) [clock format $result(when) -gmt 1]"
228                                        putserv "PRIVMSG $nick :Question: $result(question)"
229                                        putserv "PRIVMSG $nick :  Answer: $result(answer)"
230                                        putserv "PRIVMSG $nick :  Report: $result(message)"
231                                }
232                                return 0
233                        }
234
235                        if {$func == "fix"} {
236                                set arg [string trim $arg]
237                                if [regexp -nocase {([0-9]+) (question|answer) (.+)} $arg matches report_id thing fix] {
238                                        putserv "PRIVMSG $nick :Attempting to fix $trivia_c(purple)$thing$trivia_c(off) from report$trivia_c(purple) $report_id"
239                                        #get question ID for this report
240                                        set sql "SELECT question_id FROM reports WHERE report_id = '$report_id'"
241                                        putloglev d * $sql
242                                        set question_id 0
243                                        trivia_db_handle eval $sql result {
244                                                set question_id $result(question_id)
245                                        }
246                                       
247                                        if {$question_id == 0} {
248                                                putserv "PRIVMSG $nick :I can't seem to find that report, sorry :("
249                                                return 0
250                                        }
251
252                                        set fix [trivia_sqlite_escape $fix]
253                                        set sql "UPDATE questions SET $thing = '$fix' WHERE question_id = '$question_id'"
254                                        putloglev d * $sql
255                                        trivia_db_handle eval $sql
256
257                                        putserv "PRIVMSG $nick :Updated!"
258                                        return 0
259                                } else {
260                                        puthelp "PRIVMSG $nick :Use: report fix <id> (question|answer) <new text>"
261                                        return 0
262                                }
263                        }
264
265                        if {$func == "done"} {
266                                set arg [string trim $arg]
267                                set arg [trivia_sqlite_escape $arg]
268                                putserv "PRIVMSG $nick :Marking report$trivia_c(purple) $arg $trivia_c(off)as done."
269                                set sql "UPDATE reports SET resolved = 'Y' WHERE report_id = '$arg'"
270                                putloglev d * $sql
271                                trivia_db_handle eval $sql
272                                return 0
273                        }
274
275                        if {$func == "delete"} {
276                                set arg [string trim $arg]
277                                set arg [trivia_sqlite_escape $arg]
278                                putserv "PRIVMSG $nick :Deleting question from report$trivia_c(purple) $arg $trivia_c(off) and marking report as done."
279                                set sql "DELETE FROM questions WHERE question_id IN (SELECT question_id FROM reports WHERE report_id = '$arg')"
280                                putloglev d * $sql
281                                trivia_db_handle eval $sql
282                                set sql "UPDATE reports SET resolved = 'Y' WHERE report_id = '$arg'"
283                                putloglev d * $sql
284                                trivia_db_handle eval $sql
285                                return 0
286                        }
287                }
288#>>>
289        }
290}
291#>>>
292
293# Handle input coming from a channel
294proc trivia_input { nick host handle channel arg } {
295#<<<
296        global trivia_channel trivia_status trivia_q_answer
297        global trivia_guesser_count trivia_guesser trivia_c
298
299        if {[string tolower $trivia_channel] != [string tolower $channel]} {
300                return 0
301        }
302
303        if [regexp -nocase "^!t(rivia)? (.+)" $arg matches cmd param] {
304                trivia_command $nick $host $handle $channel $param
305                return 0
306        }
307
308        if [string match -nocase "!start" $arg] {
309                if {$trivia_status > 0} {
310                        return
311                }
312                puthelp "PRIVMSG $trivia_channel :YOU'RE DOING IT WRONG"
313        }
314
315        if [regexp -nocase "^!t(rivia)?$" $arg] {
316                if {$trivia_status == 1} {
317                        puthelp "PRIVMSG $trivia_channel :!trivia ... ?"
318                        return 0
319                } else {
320                        puthelp "PRIVMSG $trivia_channel :Perhaps you want $trivia_c(purple)!trivia start"
321                        return 0
322                }
323        }
324
325        # need to be running below here
326        if {$trivia_status == -1} {
327                return 0
328        }
329
330        if {$trivia_q_answer == ""} {
331                return 0
332        }
333
334        #see if someone else is playing
335        if {($nick == $trivia_guesser) && ($nick != "NoTopic")} {
336                incr trivia_guesser_count
337                putloglev d * "$nick has talked $trivia_guesser_count times in a row..."
338        } else {
339                set trivia_guesser_count 0
340                set trivia_guesser $nick
341        }
342
343        #tidy the string up
344        set arg [string tolower $arg]
345        set arg [string trim $arg]
346        if {$arg == [string tolower $trivia_q_answer]} {
347                # try to stop any other output
348                clearqueue server
349                trivia_correct $nick
350                return 0
351        }
352
353        #if they didn't get it right, and it's been more than 20 lines, taunt!
354        if {($trivia_guesser_count > 0) && (($trivia_guesser_count % 20)) == 0} {
355                putserv "PRIVMSG $trivia_channel :Playing with yourself, $nick? ;)"
356                putlog "Is $nick playing with themselves?"
357        }
358}
359#>>>
360
361# Someone got it right!
362proc trivia_correct { nick } {
363#<<<
364        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status
365        global trivia_timer trivia_delay trivia_db_handle trivia_unanswered trivia_run_qty trivia_run_last trivia_run_nick trivia_c
366        global trivia_score_time trivia_time_left_warning trivia_asking_question trivia_current_leader trivia_q_timestamp
367
368        if {$trivia_status != 1} {
369                #something strange going on
370                return 0
371        }
372
373        trivia_killtimer
374        set answer $trivia_q_answer
375        set trivia_q_answer ""
376        set newuser 0
377        set trivia_asking_question 0
378
379        set speed [expr [clock seconds] - $trivia_q_timestamp]
380
381        set speedword ""
382        if {$speed <= 1} {
383                set speedword [trivia_random_element [list "POW! 0 to correct in under a second!" "Faster than a speeding fast thing!" "Even I didn't get it that quick, and I've just got to do a database lookup!"]]
384        } elseif {$speed < 7} {
385                set speedword [trivia_random_element [list "WHOOSH! 0 to correct in $speed seconds!" "%% shows their unassailable knowledge of whatever that question was about by getting it in $speed seconds" "Set course for correctsville, Commander %%. Ahead warp [expr 10 - $speed]!" "Caffeine abuse pays off for %% with a speedy time of $speed seconds" "Faster than a speeding triviabullet!"]]
386        }
387
388        set uid [trivia_get_uid $nick]
389        if {$uid == 0} {
390                putlog "$nick does not have entry in database... creating"
391                set uid [trivia_create_user $nick]
392                set newuser 1
393        }
394
395        putlog "$nick has uid $uid"
396
397        set old_leader [trivia_leader]
398
399        trivia_incr_score $uid
400
401        regsub -all -nocase "%%" $speedword "$trivia_c(purple)$nick$trivia_c(off)" speedword
402
403        putquick "PRIVMSG $trivia_channel :Congratulations $trivia_c(purple)$nick$trivia_c(off)! The answer was$trivia_c(purple) $answer$trivia_c(off)."
404        if {$speedword != ""} {
405                putquick "PRIVMSG $trivia_channel :$speedword"
406        }
407
408        trivia_bmotion_send "winner" "$nick $answer"
409        if {$newuser == 1} {
410          putquick "PRIVMSG $trivia_channel :Welcome to our newest player,  $trivia_c(purple)$nick$trivia_c(off) :)"
411        }       
412        putquick "PRIVMSG $trivia_channel :Rankings: [trivia_near_five3 $uid]"
413
414        set leader [trivia_leader]
415
416        if {($leader != $old_leader) && ($leader != -1) && ($old_leader != -1)} {
417                putquick "PRIVMSG $trivia_channel :$trivia_c(purple) $nick $trivia_c(off) has taken the lead!"
418        }
419
420        #set score [trivia_get_score $uid]
421        #putserv "PRIVMSG $trivia_channel :$nick now has $score points."
422
423        set trivia_timer [utimer $trivia_delay trivia_start_round]
424        set trivia_unanswered 0
425        if {$trivia_run_last == $uid} {
426                incr trivia_run_qty
427                if {$trivia_run_qty > 2} {
428                        putquick "PRIVMSG $trivia_channel :$nick [trivia_get_run $trivia_run_qty] $trivia_run_qty in a row!"
429                }
430        } else {
431                #end of streak
432                if {$trivia_run_qty > 2} {
433                        putquick "PRIVMSG $trivia_channel :$nick ended $trivia_run_nick's winning spree."
434                }
435                set trivia_run_qty 1
436                set trivia_run_last $uid
437                set trivia_run_nick $nick
438        }
439
440        if {[rand 100] > 95} {
441                putserv "PRIVMSG $trivia_channel :Remember, to report a problem with a question or answer, type $trivia_c(purple)!trivia report <description of problem>"
442        }
443
444        if {$trivia_score_time <= [clock seconds]} {
445                trivia_end_week
446        } else {
447                if {[expr $trivia_score_time - [clock seconds]] < $trivia_time_left_warning} {
448                        set diff [expr $trivia_score_time - [clock seconds]]
449                        set diff $diff.0
450                        set nearness [expr $diff / $trivia_time_left_warning * 100]
451                        set chance [rand 100]
452                        putlog "diff = $diff, nearness = $nearness, chance = $chance"
453                        if {$chance < $nearness} {
454                                putserv "PRIVMSG $trivia_channel :[trivia_score_time_left] until the end of this game!"
455                        }
456                }
457        }
458
459        trivia_check_rehash
460}
461#>>>
462
463#See if we need to rehash
464proc trivia_check_rehash { } {
465#<<<
466  global trivia_must_rehash trivia_channel trivia_c
467  if {$trivia_must_rehash == 1} {
468    putquick "PRIVMSG $trivia_channel :$trivia_c(red)### Please wait, reloading trivia script ###"
469                trivia_killtimer
470    rehash
471  }
472}
473#>>>
474
475# Turn a winning spree into text
476proc trivia_get_run { row } {
477#<<<
478        global trivia_channel trivia_c
479        switch $row {
480                3 {
481                        return "is on a winning spree!"
482                }
483                4 {
484                        putquick "PRIVMSG $trivia_channel :$trivia_c(realblue)QUAD DAMAGE!"
485                        return "is on a roll ..."
486                }
487                5 {
488                        return "is on a rampage!"
489                }
490                6 {
491                        return "is unstoppable!"
492                }
493                8 {
494                        return "is on a Google spree!"
495                }
496                10 {
497                        return "is GODLIKE!"
498                }
499                12 {
500                  return "needs to get out more."
501                }
502        }
503        return "is on a roll ..."
504}
505#>>>
506
507# Escape stuff for SQL
508proc trivia_sqlite_escape { text } {
509#<<<
510        return [string map {' ''} $text]
511}
512#>>>
513
514# Get someone's user ID from their nick
515proc trivia_get_uid { nick } {
516#<<<
517        global trivia_db_handle
518
519        putloglev 4 * "trivia_get_uid ($nick)"
520
521        set nick [trivia_sqlite_escape $nick]
522        set sql "SELECT user_id FROM users WHERE user_name = '$nick'"
523        trivia_db_handle eval $sql {
524                return $user_id
525        }
526        return 0
527}
528#>>>
529
530# Get a period
531proc trivia_get_period { } {
532#<<<
533        return [expr [clock scan "last friday 23:59" -gmt true] + 60]
534}
535#>>>
536
537# Get a score from a UID
538proc trivia_get_score { user_id } {
539#<<<
540        global trivia_db_handle
541
542        putloglev 4 * "trivia_get_score ($user_id)"
543
544        set dt [trivia_get_period]
545
546        set sql "SELECT COUNT(*) AS yarr FROM scores WHERE dt > '$dt' AND user_id='$user_id'"
547        trivia_db_handle eval $sql {
548                return $yarr
549        }
550        return 0
551}
552#>>>
553
554# Turn a timestamp into a date
555proc trivia_ts_to_date { ts } {
556#<<<
557  return [clock format $ts -format "%Y/%m/%d %H:%M"]
558}
559#>>>
560
561# Get someone's userinfo from their UID
562proc trivia_get_userinfo { user_id } {
563#<<<
564        global trivia_db_handle trivia_channel
565
566        putloglev 4 * "trivia_get_userinfo ($user_id)"
567        set donestats 0
568
569        set sql "SELECT user_name, user_score, user_last, user_reg FROM users WHERE user_id = '$user_id'"
570
571        trivia_db_handle eval $sql {
572                if {$user_last == ""} {
573                  set last "Unknown"
574                } else {
575                        set last [trivia_ts_to_date $user_last]
576                }
577
578                if {$user_reg == ""} {
579                        set reg "Unkown"
580                } else {
581                        set reg [trivia_ts_to_date $user_reg]
582                }
583
584                putserv "PRIVMSG $trivia_channel :Trivia stats for $user_name:"
585                putserv "PRIVMSG $trivia_channel :   Current score: $user_score"
586                putserv "PRIVMSG $trivia_channel :      First seen: $reg"
587                putserv "PRIVMSG $trivia_channel :     Last scored: $last"
588                set donestats 1
589        }
590
591        set sql "SELECT COUNT(dt) AS score FROM scores WHERE dt > [trivia_get_period] AND user_id = '$user_id'"
592        if {$donestats} {
593                trivia_db_handle eval $sql {
594                        putserv "PRIVMSG $trivia_channel :Points this week: $score"
595                        putserv "PRIVMSG $trivia_channel :  Weekly Ranking: [trivia_get_rank $user_id]"
596                }
597        } else {
598                putserv "PRIVMSG $trivia_channel :No stats found"
599        }
600}
601#>>>
602
603# Get someone's stats from their username
604proc trivia_user_stats { user_name } {
605#<<<
606        global trivia_channel
607
608        set uid [trivia_get_uid $user_name]
609        if {$uid == 0} {
610                putserv "PRIVMSG $trivia_channel :Unknown user '$user_name' (is the case right?)"
611                return
612        }
613
614        trivia_get_userinfo $uid
615}
616#>>>
617
618# Increase a UID's score
619proc trivia_incr_score { id { howmuch 1 } } {
620#<<<
621        global trivia_db_handle
622
623        putloglev 4 * "trivia_incr_score ($id, $howmuch)"
624
625        set sql "UPDATE users SET user_last = [clock seconds], user_points = user_points + 1 WHERE user_id = '$id'"
626        trivia_db_handle eval $sql
627
628        set sql "INSERT INTO scores VALUES ('$id', '[clock seconds]')"
629        trivia_db_handle eval $sql
630}
631#>>>
632
633# Create a new user
634proc trivia_create_user { nick } {
635#<<<
636        global trivia_db_handle
637
638        putloglev 4 * "trivia_create_user ($nick)"
639
640        set nick [trivia_sqlite_escape $nick]
641        set sql "INSERT INTO users VALUES (null, '$nick', '', 0, [clock seconds], [clock seconds], 0)"
642        trivia_db_handle eval $sql
643
644        set uid [trivia_db_handle last_insert_rowid]
645
646        return $uid
647}
648#>>>
649
650# Handle a !trivia command
651proc trivia_command { nick host handle channel param } {
652#<<<
653        global trivia_channel trivia_status trivia_flag trivia_admin trivia_c
654
655        set arg ""
656        regexp {^([^ ]+)( .+)?$} $param matches cmd arg
657        set param [string tolower $cmd]
658        set arg [string trim $arg]
659
660
661        putloglev d *  "trivia command: $param from: $nick ($arg)"
662
663        if {[matchattr $handle |$trivia_admin $trivia_channel] && ($param != "enable") && ($trivia_status == -1)} {
664                return 0
665        }
666
667        if [regexp -nocase "^(score|place)( .+)?" $param] {
668                putserv "PRIVMSG $trivia_channel :[trivia_score $arg $nick]"
669                if [string match -nocase $nick $arg] {
670                        putserv "PRIVMSG $trivia_channel :(You know putting your own nick is optional, right? :)"
671                }
672                return 0
673        }
674
675        if {$param == "top10"} {
676                putserv "PRIVMSG $trivia_channel :[trivia_get_top10]"
677                return 0
678        }
679
680        if {$param == "info"} {
681                trivia_user_stats $arg
682                return 0
683        }
684
685        if {$param == "start"} {
686                trivia_start
687                return 0
688        }
689
690        if {$param == "report"} {
691                trivia_report $nick $arg
692                return 0
693        }
694
695        if {$param == "countdown"} {
696                trivia_countdown
697                return 0
698        }
699
700  if {![matchattr $handle |$trivia_flag $channel]} {
701    putserv "PRIVMSG $nick :use: !trivia \[score|top10|start|report\]"
702    return 0
703  }
704
705  if {$param == "stop"} {
706    trivia_stop
707    return 0
708  }
709
710
711        if {$param == "skip"} {
712                trivia_skip $nick
713                return 0
714        }
715
716        if {$param == "stats"} {
717                trivia_stats
718                return 0
719        }
720
721        if {![matchattr $handle |$trivia_admin $channel]} {
722                putserv "PRIVMSG $nick :use: !trivia \[score|top10|start|stop|skip|stats\]"
723                return 0
724        }
725
726        if {$param == "disable"} {
727                trivia_disable
728                return 0
729        }
730
731        if {$param == "enable"} {
732                trivia_enable
733                return 0
734        }
735
736        if {$param == "merge"} {
737                trivia_merge $nick $arg
738                #puthelp "PRIVMSG $trivia_channel :Score merging is disabled"
739                return 0
740        }
741
742        if {$param == "rehash"} {
743                trivia_rehash
744                return 0
745        }
746
747        putserv "PRIVMSG $nick :use: !trivia \[start|stop|score|top10|skip|stats|enable|disable|merge\]"
748        return 0
749}
750#>>>
751
752# Rehash
753proc trivia_rehash { } {
754#<<<
755        global trivia_status trivia_channel trivia_must_rehash
756        if {$trivia_must_rehash == 1} {
757                putserv "PRIVMSG $trivia_channel :! Reloading trivia now..."
758                rehash
759                return 0
760        }
761
762        if {$trivia_status != 1} {
763                putserv "PRIVMSG $trivia_channel :! Reloading trivia now..."
764                rehash
765                return 0
766        }
767  set trivia_must_rehash 1
768        putserv "PRIVMSG $trivia_channel :Trivia will reload after current round"
769}
770#>>>
771
772# Disable the script
773proc trivia_disable { } {
774#<<<
775        global trivia_status trivia_channel
776
777        if {$trivia_status == 1} {
778                #stop the current game
779                trivia_stop
780        }
781
782        set trivia_status -1
783        putserv "PRIVMSG $trivia_channel :Trivia disabled."
784        return 0
785}
786#>>>
787
788proc trivia_ping { } {
789        return
790}
791
792# Enable the script
793proc trivia_enable {} {
794#<<<
795        global trivia_status trivia_channel trivia_db_handle
796
797        set trivia_status 0
798        putserv "PRIVMSG $trivia_channel :Trivia enabled."
799
800        trivia_ping
801
802        return 0
803}
804#>>>
805
806#Make a hint
807proc trivia_make_hint { hint answer } {
808#<<<
809        global trivia_debug_mode
810
811        set hint [string toupper $hint]
812        set answer [string toupper $answer]
813
814        set answer_words [split $answer { }]
815        set final_hint ""
816
817        #are we making the very first hint?
818        if {$hint == ""} {
819                foreach word $answer_words {
820                        append final_hint [string repeat "_" [string length $word]]
821                        append final_hint " "
822                }
823
824                set final_hint [string trim $final_hint]
825
826                #now put the punctuation in
827                set letters [split $answer {}]
828                set i 0
829                foreach letter $letters {
830                        if {![regexp -nocase {[A-Z0-9 ]} $letter]} {
831                                set final_hint [string replace $final_hint $i $i $letter]
832                        }
833                        incr i
834                }
835                return [string trim $final_hint]
836        }
837
838        # explode the into words
839        set hint_words [split $hint { }]
840
841
842        set i 0
843
844        foreach word $hint_words {
845                set answer_word [lindex $answer_words $i]
846                putloglev 1 * "considering $answer_word ($word)"
847
848                #are we on the first iteration?
849                if [regexp "^_+$" $word] {
850                        #use the first letter
851                        set letters [string length $word]
852
853                        #don't hint for single-letter words
854                        if {$letters > 1} {
855                                set word [string index $answer_word 0]
856                                append word [string repeat "_" [expr $letters - 1]]
857                        } else {
858                                set word "_"
859                        }
860                        append final_hint "$word "
861                } else {
862                        #not the first iteration so figure out where the gaps are
863                        set gaps [list]
864                        set letters [split $word {}]
865                        set j 0
866                        foreach letter $letters {
867                                if {$letter == "_"} {
868                                        lappend gaps $j
869                                }
870                                incr j
871                        }
872                        if {[llength $gaps] <= 1} {
873                                #eek no letters to replace, or only one gap
874                                putloglev 1 * "  insufficient gaps, using $word"
875                                append final_hint "$word "
876                        } else {
877                                #now we pick a random letter position
878                                set pos [trivia_random_element $gaps]
879                                putloglev 1 * "  filling in $pos"
880                                set word [string replace $word $pos $pos [string index $answer_word $pos]]
881                                putloglev 1 * "  --> $word"
882                                append final_hint "$word "
883                        }
884                }
885                incr i
886        }
887        set final_hint [string trim $final_hint]
888        if {$trivia_debug_mode == 1} {
889                return $answer
890        }
891
892        return $final_hint
893}
894#>>>
895
896# Fetch a question
897proc trivia_get_question { } {
898#<<<
899        global trivia_db_handle trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_channel
900
901        set trivia_q_id ""
902
903        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, random() LIMIT 1"
904        trivia_db_handle eval $sql {
905                set trivia_q_id $question_id
906                set trivia_q_cat $cat_name
907                set trivia_q_question $question
908                set trivia_q_answer [string toupper $answer]
909                set trivia_q_hint ""
910
911                #tidy up question and answer
912                regsub -all "  +" $trivia_q_question " " trivia_q_question
913                regsub -all "  +" $trivia_q_answer " " trivia_q_answer
914
915                set trivia_q_question [string trim $trivia_q_question]
916                set trivia_q_answer [string trim $trivia_q_answer]
917        } 
918
919        if {$trivia_q_id == ""} {
920                return
921        }
922
923        #update the times used
924        set sql "UPDATE questions SET count = count + 1 WHERE question_id = '$trivia_q_id'"
925        trivia_db_handle eval $sql
926}
927#>>>
928
929# Start a round
930proc trivia_start_round { } {
931#<<<
932        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
933        global trivia_asking_question trivia_delay botnick trivia_q_timestamp
934
935        if {$trivia_status != 1} {
936                #we're switched off, abort
937                return 0
938        }
939
940        #init variables
941        set trivia_q_id ""
942        set trivia_q_cat ""
943        set trivia_q_question ""
944        set trivia_q_answer ""
945        set trivia_q_hint ""
946
947        putlog "Fetching next question..."
948
949        trivia_get_question
950
951        if {$trivia_q_id == ""} {
952                putlog "Couldn't init trivia round, aborting."
953                return
954        }
955
956        putlog "Successfully fetched question $trivia_q_id from database"
957        putloglev 4 * "question = $trivia_q_question"
958        putloglev 4 * "answer   = $trivia_q_answer"
959
960        set trivia_q_attempts 1
961
962        set trivia_last_qid $trivia_q_id
963
964        set trivia_asking_question 1
965
966        trivia_bmotion_send "start" "$trivia_channel $trivia_delay $botnick"
967        set trivia_q_timestamp [clock seconds]
968
969        trivia_round
970
971}
972#>>>
973
974# Run a round
975proc trivia_round { } {
976#<<<
977        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status
978        global trivia_timer trivia_speed trivia_c trivia_last_ts
979
980        if {$trivia_status != 1} {
981                #we're switched off, abort
982                return 0
983        }
984
985        if {$trivia_q_attempts == 5} {
986                trivia_end_round
987                return 0
988        }
989
990        if {$trivia_q_answer == ""} {
991                return 0
992        }
993
994        #update the hint
995        set trivia_q_hint [trivia_make_hint $trivia_q_hint $trivia_q_answer]
996        putlog "hint is $trivia_q_hint"
997
998        #say our stuff
999        if {$trivia_q_attempts > 1} {
1000                set hint " \[[expr $trivia_q_attempts - 1] of 3\]"
1001        } else {
1002                set hint ""
1003        }
1004
1005        set split_question [trivia_question_split $trivia_q_question]
1006
1007        putquick "PRIVMSG $trivia_channel :$trivia_c(red)--== Trivia ==--$trivia_c(off) \[category: \002$trivia_q_cat\002\]"
1008        foreach q $split_question {
1009                if {$q != ""} {
1010                        putquick "PRIVMSG $trivia_channel :$trivia_c(blue) [trivia_question_inject $q]"
1011                }
1012        }
1013        #set new_question [trivia_question_inject $trivia_q_question]
1014        #putquick "PRIVMSG $trivia_channel :$trivia_c(blue) $new_question"
1015        putquick "PRIVMSG $trivia_channel :Hint$hint: [trivia_explode $trivia_q_hint]"
1016
1017        incr trivia_q_attempts
1018
1019        trivia_bmotion_send "hint" [string map {_ .} $trivia_q_hint]
1020
1021        set trivia_last_ts [clock seconds]
1022
1023        global trivia_must_rehash
1024  if {$trivia_must_rehash != 2} {
1025                set trivia_timer [utimer $trivia_speed trivia_round]
1026        }
1027}
1028#>>>
1029
1030# Make it harder for things to break questions (inject bold codes)
1031proc trivia_question_inject { question } {
1032#<<<
1033  putlog "trivia_question_inject $question"
1034        #inject random bold/underline/colour codes into question
1035        global trivia_c
1036
1037        set l [string length $question]
1038        putlog "length: $l"
1039        if {$l < 1} {
1040          return $question
1041        }
1042        set pos [rand $l]
1043        set first [string range $question 0 $pos]
1044        incr pos
1045        set second [string range $question $pos end]
1046        switch [rand 1] {
1047                0 {
1048                        putlog "question_inject: using bold at pos $pos"
1049                        return $first$trivia_c(bold)$trivia_c(bold)$second
1050                }
1051                1 {
1052                        putlog "question_inject: using purple at pos $pos"
1053                        return $first$trivia_c(purple)$trivia_c(off)$second
1054                }
1055        }
1056        return $question
1057}
1058#>>>
1059
1060# Make it harder for things to break questions (inject line breaks)
1061proc trivia_question_split { question } {
1062#<<<
1063  putlog "trivia_question_split $question"
1064        #explodes a question into two lines at word boundaries, if it's long enough
1065        #don't split unscrambles incorrectly
1066        if [regexp -nocase "(unscramble .+:) (\[A-Z \]+)" $question matches first second] {
1067                return [list $first $second]
1068        }
1069        set words [split $question " "]
1070        set wordcount [llength $words]
1071        if {$wordcount < 4} {
1072          putlog "aborting, too short"
1073                return [list $question]
1074        }
1075
1076        #enough words to split
1077        #we want at least two on the first line
1078        putlog "wordcount: $wordcount"
1079        incr wordcount -2
1080        if {$wordcount < 0} {
1081                return [list $question]
1082        }
1083        set pos [rand $wordcount]
1084        incr pos 2
1085        putlog "picked pos $pos"
1086        set wordlist [list]
1087        set i 0
1088        set line ""
1089        foreach word $words {
1090                #putlog "word = $word, i = $i"
1091                append line "$word "
1092                if {$i == $pos} {
1093                        #putlog "splitting here, line = $line"
1094                        lappend wordlist [string trim $line]
1095                        set line ""
1096                }
1097                incr i
1098        }
1099        #putlog "done, appending $line to list"
1100        if {$line != ""} {
1101                lappend wordlist [string trim $line]
1102        }
1103        #putlog "split question list is: $wordlist"
1104        return $wordlist
1105}
1106#>>>
1107
1108# Finish a round (without a winner)
1109proc trivia_end_round { } {
1110#<<<
1111        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status
1112        global trivia_timer trivia_delay trivia_db_handle trivia_unanswered
1113        global trivia_run_last trivia_run_nick trivia_run_qty trivia_c trivia_score_time trivia_asking_question trivia_time_left_warning
1114
1115        if {$trivia_status != 1} {
1116                #we're switched off, abort
1117                return 0
1118        }
1119
1120        set trivia_asking_question 0
1121
1122        trivia_bmotion_send "winner" "* $trivia_q_answer"
1123        trivia_bmotion_send "stop" ""
1124
1125        set trivia_q_answer [string toupper $trivia_q_answer]
1126        putquick "PRIVMSG $trivia_channel :Time's up! Nobody got it right. The answer was$trivia_c(purple) $trivia_q_answer"
1127        set trivia_q_answer ""
1128
1129        incr trivia_unanswered
1130        if {$trivia_run_qty > 2} {
1131                putserv "PRIVMSG $trivia_channel :So much for $trivia_run_nick's winning spree."
1132        }
1133        set trivia_run_last 0
1134        set trivia_run_qty 0
1135        set trivia_run_nick ""
1136
1137        if {[rand 100] > 90} {
1138                putserv "PRIVMSG $trivia_channel :Remember, to report a problem with a question or answer, type $trivia_c(purple)!trivia report <description of problem>"
1139        }
1140
1141        if {$trivia_unanswered > 3} {
1142                putserv "PRIVMSG $trivia_channel :Four unanswered in a row, stopping the game."
1143                putserv "PRIVMSG $trivia_channel :You can restart it with $trivia_c(purple)!t start"
1144                set trivia_status 0
1145        } else {
1146                set trivia_timer [utimer $trivia_delay trivia_start_round]
1147                if {$trivia_score_time <= [clock seconds]} {
1148                        trivia_end_week
1149                } else {
1150                if {[expr $trivia_score_time - [clock seconds]] < $trivia_time_left_warning} {
1151                        set diff [expr $trivia_score_time - [clock seconds]]
1152                        set diff $diff.0
1153                        set nearness [expr $diff / $trivia_time_left_warning * 100]
1154                        set chance [rand 100]
1155                        putlog "diff = $diff, nearness = $nearness, chance = $chance"
1156                        if {$chance < $nearness} {
1157                                putserv "PRIVMSG $trivia_channel :[trivia_score_time_left] until the end of this game!"
1158                        }
1159                }
1160                }
1161                trivia_check_rehash
1162        }
1163}
1164#>>>
1165
1166# Skip the rest of this question
1167proc trivia_skip { nick } {
1168#<<<
1169        global trivia_q_id trivia_q_cat trivia_q_question trivia_q_answer trivia_q_hint trivia_q_attempts trivia_channel trivia_status
1170        global trivia_timer trivia_delay trivia_db_handle trivia_unanswered trivia_score_time
1171
1172        if {$trivia_status != 1} {
1173                #we're switched off, abort
1174                return 0
1175        }
1176
1177        if {$trivia_q_answer == ""} {
1178                #no round in progress
1179                return 0
1180        }
1181
1182        set trivia_q_question ""
1183        set trivia_q_answer ""
1184
1185        trivia_killtimer
1186
1187        trivia_bmotion_send "stop" ""
1188
1189        putserv "PRIVMSG $trivia_channel :Skipping this question by $nick's request."
1190        set trivia_timer [utimer $trivia_delay trivia_start_round]
1191        if {$trivia_score_time <= [clock seconds]} {
1192                trivia_end_week
1193        }
1194}
1195#>>>
1196
1197# Utility function to fetch a random item from a list
1198proc trivia_random_element { l } {
1199#<<<
1200        return [lindex $l [rand [llength $l]]]
1201}
1202#>>>
1203
1204# Start the game
1205proc trivia_start { } {
1206#<<<
1207        global trivia_status trivia_channel trivia_unanswered trivia_run_last trivia_run_qty trivia_c trivia_must_rehash trivia_db_handle
1208
1209        if {$trivia_status == 1} {
1210                putserv "PRIVMSG $trivia_channel :Trivia is already running."
1211                return 0
1212        }
1213
1214        if {$trivia_status == -1} {
1215                putserv "PRIVMSG $trivia_channel :Trivia is currently disabled."
1216                return 0
1217        }
1218
1219        trivia_ping
1220
1221        # go go go
1222        set trivia_status 1
1223        if {$trivia_must_rehash == 2 } {
1224                putquick "PRIVMSG $trivia_channel :$trivia_c(blue)### Resuming trivia game ###" -next
1225        } else {
1226                putquick  "PRIVMSG $trivia_channel :Trivia game started!" -next
1227        }
1228
1229        #trivia_stats
1230
1231        putquick "PRIVMSG $trivia_channel :[trivia_score_time_left] left until end of this game!"
1232
1233        #try to find last week's winner
1234        set sql "SELECT winners.user_id, users.user_name FROM winners LEFT JOIN users USING(user_id) ORDER BY dt DESC, score DESC LIMIT 1"
1235        putloglev d * $sql
1236        trivia_db_handle eval $sql {
1237                putquick "PRIVMSG $trivia_channel :Last week's winner was$trivia_c(purple) [string toupper $user_name]$trivia_c(off)!"
1238        }
1239
1240        set trivia_unanswered 0
1241        set trivia_run_last 0
1242        set trivia_run_qty 0
1243
1244        trivia_start_round
1245        return 0
1246}
1247#>>>
1248
1249# Stop the game
1250proc trivia_stop { } {
1251#<<<
1252        global trivia_channel trivia_status
1253
1254        if {$trivia_status == 1} {
1255                clearqueue server
1256                putserv "PRIVMSG $trivia_channel :Trivia game stopped."
1257                set trivia_status 0
1258                trivia_bmotion_send "stop" ""
1259                trivia_killtimer
1260        }
1261        return 0
1262}
1263#>>>
1264
1265# Kill our timer
1266proc trivia_killtimer { } {
1267#<<<
1268        global trivia_timer
1269
1270        if {$trivia_timer != ""} {
1271                killutimer $trivia_timer
1272        }
1273}
1274#>>>
1275
1276# Utility function to explode line into letters
1277proc trivia_explode { line } {
1278#<<<
1279        set letters [split $line {}]
1280        set newline ""
1281        foreach letter $letters {
1282                append newline "$letter "
1283        }
1284        return [string trim $newline]
1285}
1286#>>>
1287
1288# Get a UID's ranking
1289proc trivia_get_rank { uid } {
1290#<<<
1291        global trivia_db_handle
1292
1293        putloglev 4 * "trivia_get_rank ($uid)"
1294
1295        set sql "SELECT user_id FROM users ORDER by user_score DESC"
1296        set dt [trivia_get_period]
1297        set sql "select user_id, count(dt) as d from scores where dt > $dt group by user_id order by d desc"
1298       
1299        set pos 0
1300        trivia_db_handle eval $sql {
1301                incr pos
1302                putloglev d * "considering user_id $user_id, score $d"
1303                if {$user_id == $uid} {
1304                        return $pos
1305                }
1306        }
1307        return 0
1308}
1309#>>>
1310
1311# Get the top 10 users
1312proc trivia_get_top10 { } {
1313#<<<
1314        global trivia_db_handle
1315
1316        set dt [trivia_get_period]
1317        set sql "select users.user_name as u, 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"
1318
1319        set output ""
1320        set index 0
1321
1322        trivia_db_handle eval $sql {
1323                incr index
1324                append output "\002$index:\002 "
1325                append output $u
1326                append output " ("
1327                append output $d
1328                append output ")  "
1329        }
1330
1331        if {$index == 0} {
1332                set output "No scores so far, everyone is equal first! \\o/"
1333        } else {
1334                set output "The top $index players are... $output"
1335        }
1336        return $output
1337}
1338#>>>
1339
1340# Fix a number into text
1341proc trivia_ordinal { number } {
1342#<<<
1343        if [regexp {1[0-9]$} $number] {
1344                return "th"
1345        }
1346
1347        set last [string range $number end end]
1348
1349        if {$last == "1"} {
1350                return "st"
1351        }
1352
1353        if {$last == "2"} {
1354                return "nd"
1355        }
1356
1357        if {$last == "3"} {
1358                return "rd"
1359        }
1360
1361        return "th"
1362}
1363#>>>
1364
1365# Get a score
1366proc trivia_score { n { nick "" } } {
1367#<<<
1368        set n [string trim $n]
1369        putloglev 4 * "trivia_score($n, $nick)"
1370
1371        if {$n == ""} {
1372                set ni $nick
1373                set o "You are"
1374        } else {
1375                set ni $n
1376                set o "$n is"
1377        }
1378
1379        set uid [trivia_get_uid $ni]
1380        set score [trivia_get_score $uid]
1381        set pos [trivia_get_rank $uid]
1382        if {$score == 0} {
1383                return "No score found for $n."
1384        }
1385        return "$o ranked $pos[trivia_ordinal $pos] with $score points."
1386}
1387#>>>
1388
1389# Turn a list into a stats list
1390proc trivia_list_to_stats { pos user_id l } {
1391#<<<
1392        putloglev 4 * "trivia_list_to_stats ($pos, $user_id, $l)"
1393        global trivia_c
1394        set uid [lindex $l 0]
1395        set nick [lindex $l 1]
1396        set score [lindex $l 2]
1397        incr pos
1398
1399        set result ""
1400        if {$user_id == $uid} {
1401                set result "$trivia_c(purple)$trivia_c(bold)"
1402        }
1403        append result "$pos[trivia_ordinal $pos]: $nick ($score)  "
1404        if {$user_id == $uid} {
1405                append result "$trivia_c(off)$trivia_c(bold)"
1406        }
1407        return $result
1408}
1409#>>>
1410
1411# Another function to get the nearest users to your score
1412proc trivia_near_five2 { uid } {
1413#<<<
1414        global trivia_db_handle trivia_c
1415
1416        set sql "SELECT user_id, user_name, user_score FROM users ORDER BY user_score DESC"
1417        set dt [trivia_get_period]
1418  set sql "select users.user_id as user_id, users.user_name as 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 count(dt) desc"
1419        putlog $sql
1420
1421        set result [list]
1422        trivia_db_handle eval $sql {
1423                set line [list]
1424                lappend line $user_id
1425                lappend line [trivia_question_inject $user_name]
1426                lappend line $user_score
1427                putlog "adding line $line"
1428                lappend result $line
1429        }
1430
1431        putlog "results list: $result"
1432
1433        set position 0
1434        foreach item $result {
1435                if {[lindex $item 0] == $uid} {
1436                        putlog "found at position $position"
1437                        break
1438                }
1439                incr position
1440        }
1441
1442        set line ""
1443
1444        if {$position > 2} {
1445                append line [trivia_list_to_stats [expr $position - 2] $uid [lindex $result [expr $position - 2]]]
1446        }
1447
1448        if {$position > 1} {
1449                append line [trivia_list_to_stats [expr $position - 1] $uid [lindex $result [expr $position - 1]]]
1450        }
1451
1452        append line [trivia_list_to_stats $position $uid [lindex $result $position]]
1453
1454        if {$position < [expr [llength $result] - 1]} {
1455                append line [trivia_list_to_stats [expr $position + 1] $uid [lindex $result [expr $position + 1]]]
1456        }
1457
1458        if {$position < [expr [llength $result] - 2]} {
1459                append line [trivia_list_to_stats [expr $position + 2] $uid [lindex $result [expr $position + 2]]]
1460        }
1461
1462        return $line
1463}
1464#>>>
1465
1466# Third function to get the nearest users to your score
1467proc trivia_near_five3 { uid } {
1468        global trivia_db_handle trivia_c
1469
1470        set sql "DROP TABLE IF EXISTS _score"
1471        putlog $sql
1472        trivia_db_handle eval $sql
1473
1474        set sql "CREATE TEMPORARY TABLE _score (user_id int, user_score int, last_score int)"
1475        putlog $sql
1476        trivia_db_handle eval $sql
1477
1478        set sql "INSERT INTO _score SELECT user_id, COUNT(dt), MAX(dt) AS user_score FROM scores GROUP BY scores.user_id"
1479        putlog $sql
1480        trivia_db_handle eval $sql
1481
1482        set outputlist ""
1483
1484
1485        # get our score
1486        set sql "SELECT user_score, last_score FROM _score WHERE user_id = $uid"
1487        set our_score ""
1488        set our_last ""
1489        trivia_db_handle eval $sql {
1490                set our_score $user_score
1491                set our_last $last_score
1492        }
1493
1494        if {$our_score == ""} {
1495                return ""
1496        }
1497
1498        if {$last_score == ""} {
1499                return ""
1500        }
1501
1502        #find our position
1503        #don't need to use last_score here because we must've just scored - making use the most recent point for this score
1504        set sql "SELECT user_id FROM _score WHERE user_score >= $our_score ORDER BY user_score DESC, last_score DESC"
1505        putlog $sql
1506        set position 1
1507        trivia_db_handle eval $sql {
1508                if {$user_id != $uid} {
1509                        incr position
1510                } else {
1511                        break
1512                }
1513        }
1514
1515        putlog "our position is $position"
1516
1517
1518        if {$position == 1} {
1519                putlog "oh we're first"
1520                #set output "$trivia_c(purple) $trivia_c(bold)"
1521                #append output "1st: [trivia_get_username $uid] ($our_score)  $trivia_c(off)$trivia_c(bold)"
1522                lappend outputlist [list $uid $our_score]
1523        } else {
1524                #find some users higher than us
1525                set sql "SELECT * FROM _score WHERE user_score > $user_score ORDER BY user_score ASC, last_score ASC LIMIT 4"
1526                putlog $sql
1527
1528                set prelist [list]
1529
1530                trivia_db_handle eval $sql {
1531                        set outputlist [concat [list [list $user_id $user_score] ] $outputlist]
1532                        putlog "outputlist is now $outputlist"
1533                }
1534
1535                # finally, us
1536                lappend outputlist [list $uid $our_score]
1537        }
1538
1539        putlog "so far, output list is $outputlist"
1540
1541        # find two people below us
1542        set sql "SELECT * FROM _score WHERE (user_score < $our_score) OR ((user_score = $our_score) AND (last_score < $our_last)) ORDER BY user_score DESC, last_score DESC LIMIT 5"
1543        putlog $sql
1544        set postlist [list]
1545        trivia_db_handle eval $sql {
1546                lappend postlist [list $user_id $user_score]
1547        }
1548
1549        putlog "postlist is $postlist"
1550
1551        set pre_size 3
1552        set post_size 2
1553
1554        if {$position == 1} {
1555                putlog "we're in first"
1556                set pre_size 1
1557                set post_size 4
1558        }
1559
1560        if {$position == 2} {
1561                putlog "we're in 2nd"
1562                set pre_size 2
1563                set post_size 3
1564        }
1565
1566        if {[llength $postlist] == 0} {
1567                putlog "no postlist, using only prelist"
1568                set pre_size 5
1569        }
1570
1571        if {[llength $postlist] == 1} {
1572                putlog "one postlist, using most prelist"
1573                set pre_size 4
1574        }
1575
1576        if {$pre_size < [llength $outputlist]} {
1577                putlog "pre_size $pre_size < length of prelist, trimming"
1578                set startpos [expr [llength $outputlist] - $pre_size]
1579                set outputlist [lrange $outputlist $startpos end]
1580        }
1581
1582        putlog "outputlist length is [llength $outputlist]"
1583
1584        set post_size [expr 5 - [llength $outputlist]]
1585
1586        if {$post_size < [llength $postlist]} {
1587                putlog "post_size calculated as $post_size and is less than list length"
1588                set postlist [lrange $postlist 0 [expr $post_size - 1]]
1589        }
1590
1591        putlog "---"
1592        putlog "pre: $outputlist"
1593        putlog "post: $postlist"
1594
1595        if {$position > 2} {
1596                set initpos [expr $position - 2]
1597        } else {
1598                set initpos 1
1599        }
1600
1601        putlog "first position on list is $initpos"
1602
1603        foreach place $postlist {
1604                lappend outputlist $place
1605        }
1606
1607        set output ""
1608
1609        foreach place $outputlist {
1610                set entry ""
1611                append entry "$initpos"
1612                append entry [trivia_ordinal $initpos]
1613                append entry ": "
1614                append entry [trivia_question_inject [trivia_get_username [lindex $place 0]]]
1615                append entry " ("
1616                append entry [lindex $place 1]
1617                append entry ")"
1618                incr initpos
1619                if {[lindex $place 0] == $uid} {
1620                        append output "$trivia_c(purple)$trivia_c(bold) $entry$trivia_c(off)$trivia_c(bold) "
1621                } else {
1622                        append output " $entry "
1623                }
1624        }
1625       
1626        putlog $output
1627        return $output
1628
1629}
1630
1631proc trivia_get_username { uid } {
1632        global trivia_db_handle
1633
1634        set sql "SELECT user_name FROM users WHERE user_id = $uid"
1635        putlog $sql
1636        return [trivia_db_handle onecolumn $sql]
1637}
1638
1639
1640# Get the current leader's UID
1641proc trivia_leader { } {
1642        global trivia_db_handle
1643
1644        set dt [trivia_get_period]
1645        set sql "SELECT user_id, count(dt) AS user_score FROM scores WHERE dt > $dt GROUP BY user_id ORDER BY COUNT(dt) DESC LIMIT 1"
1646        set uid -1
1647        trivia_db_handle eval $sql {
1648                set uid $user_id
1649        }
1650
1651        return $uid
1652}
1653
1654# Get some stats from the DB
1655proc trivia_stats { } {
1656#<<<
1657        global trivia_db_handle trivia_channel
1658
1659        set sql "SELECT COUNT(*) AS total FROM questions LEFT JOIN categories USING (cat_id) WHERE categories.cat_enabled = 1;"
1660        set stat_total_questions [trivia_db_handle eval $sql]
1661
1662        set sql "SELECT COUNT(*) AS total FROM categories WHERE cat_enabled = 1"
1663        set stat_total_cats [trivia_db_handle eval $sql]
1664
1665        putserv "PRIVMSG $trivia_channel :Using\002 $stat_total_questions\002 questions in\002 $stat_total_cats\002 categories."
1666}
1667#>>>
1668
1669# Merge two users
1670proc trivia_merge { nick param } {
1671#<<<
1672        global trivia_db_handle
1673
1674        putloglev 4 * "trivia_merge ($nick, $param)"
1675
1676        if [regexp {^([^ ]+) (.+)$} $param matches nick1 nick2] {
1677                set olduid [trivia_get_uid [trivia_sqlite_escape $nick1]]
1678                set newuid [trivia_get_uid [trivia_sqlite_escape $nick2]]
1679
1680                if {$olduid == 0} {
1681                        puthelp "PRIVMSG $nick :Can't find user '$nick1'"
1682                        return 0
1683                }
1684
1685                if {$newuid == 0} {
1686                        puthelp "PRIVMSG $nick :Can't find user '$nick2'"
1687                        return 0
1688                }
1689
1690                puthelp "PRIVMSG $nick :Meging score for $nick1 into score for $nick2"
1691                set sql "UPDATE scores SET user_id=$newuid WHERE user_id=$olduid"
1692                trivia_db_handle eval $sql
1693
1694                set newscore [trivia_get_score $newuid]
1695                puthelp "PRIVMSG $nick :$nick2 now has $newscore points."
1696
1697                set sql "DELETE FROM users WHERE user_id = $olduid"
1698                trivia_db_handle eval $sql
1699                puthelp "PRIVMSG $nick :User $nick1 has been deleted."
1700                return 0
1701        } else {
1702                puthelp "PRIVMSG $nick :Use: !trivia merge <olduser> <newuser>"
1703                puthelp "PRIVMSG $nick :  olduser's score is merged with newuser's and olduser is deleted."
1704        }
1705}
1706#>>>
1707
1708# Report a broken question
1709proc trivia_report { nick msg } {
1710#<<<
1711        global trivia_channel trivia_db_handle trivia_last_qid trivia_c
1712
1713        if {$trivia_last_qid == 0} {
1714                puthelp "PRIVMSG $trivia_channel :Sorry, unable to work out which question to report on :("
1715                return 0
1716        }
1717
1718        set nick [trivia_sqlite_escape $nick]
1719        set msg [trivia_sqlite_escape $msg]
1720
1721        set sql "INSERT INTO reports VALUES (null, [clock seconds], '$nick', '$trivia_last_qid', '$msg', 'N')"
1722        trivia_db_handle eval $sql
1723        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)."
1724        set trivia_last_qid 0
1725}
1726#>>>
1727
1728### WATCHDOG STUFF <<<
1729# Watchdog timer to make sure we're not ruined
1730proc trivia_watchdog { } {
1731#<<<
1732        global trivia_last_ts trivia_watchdog_timer trivia_status trivia_channel trivia_delay trivia_speed
1733
1734        putloglev d * "trivia watchdog: tick"
1735
1736        # slow down if we've never asked a question or we're stopped
1737        if {($trivia_last_ts == 0) || ($trivia_status == 0)} {
1738                putloglev 1 * "trivia is not running, slowing down watchdog"
1739                set trivia_watchdog_timer [utimer 45 trivia_watchdog]
1740                return 0
1741        }
1742
1743        set current_ts [clock seconds]
1744        set difference [expr $current_ts - $trivia_last_ts]
1745
1746        set trivia_limit [expr $trivia_delay + $trivia_speed + 5]
1747
1748        putloglev 1 * "trivia watchdog: current: $current_ts, last: $trivia_last_ts, difference: $difference, max: $trivia_limit"
1749
1750        if {$difference > $trivia_limit} {
1751                if {$trivia_status == 1} {
1752                        putlog "watchdog: trivia is broken"
1753                        putquick "PRIVMSG $trivia_channel :Oops, I think I'm broken. Attempting to recover..."
1754                        set trivia_status 0
1755                        trivia_start
1756                }
1757        }
1758
1759        set timer_interval [expr $trivia_delay * 2]
1760
1761        set trivia_watchdog_timer [utimer 10 trivia_watchdog]
1762        return 0
1763}
1764#>>>
1765
1766# Kill the watchdog timeer
1767proc trivia_killwatchdog { } {
1768#<<<
1769        global trivia_watchdog_timer
1770
1771  set alltimers [utimers]
1772  foreach t $alltimers {
1773    putloglev 1 * "checking timer $t"
1774    set t_function [lindex $t 1]
1775    set t_name [lindex $t 2]
1776    set t_function [string tolower $t_function]
1777                if {$t_function == "trivia_watchdog"} {
1778                        putloglev d * "killing timer $t_name"
1779      killutimer $t_name
1780                }
1781
1782                if {$t_function == "trivia_score_rot_timer"} {
1783                        putloglev d * "killing timer $t_name"
1784                        killutimer $t_name
1785                }
1786  }
1787
1788        unset trivia_watchdog_timer
1789}
1790#>>>
1791
1792trivia_killwatchdog
1793set trivia_watchdog_timer [utimer 45 trivia_watchdog]
1794#>>>
1795
1796#<<< SCORE ROTATION STUFF
1797
1798#take this week's scores and figure out this week's winners
1799proc trivia_score_winners { } {
1800        #<<<
1801        global trivia_db_handle trivia_channel
1802
1803        set winners [list]
1804
1805        set now [clock seconds]
1806
1807        set updates [list]
1808       
1809        #knock off a week
1810        set cutoff [expr $now - 604800]
1811       
1812        set sql "SELECT user_id, COUNT(*) AS score FROM scores WHERE dt > $cutoff GROUP BY user_id ORDER BY score DESC LIMIT 5"
1813        putloglev d * $sql
1814
1815        trivia_db_handle eval $sql {
1816                lappend winners [list $user_id $score]
1817        }
1818
1819        set winner_name [list]
1820
1821        foreach winner $winners {
1822                set sql "SELECT user_name FROM users WHERE user_id = '[trivia_sqlite_escape [lindex $winner 0]]'"
1823                putloglev d * $sql
1824                trivia_db_handle eval $sql {
1825                        lappend winner_name [list $user_name [lindex $winner 0] [lindex $winner 1]]
1826                }
1827        }
1828               
1829        putlog $winners
1830        putlog $winner_name
1831
1832        putserv "PRIVMSG $trivia_channel :This week's winners are:"
1833        set position 1
1834        foreach winner $winner_name {
1835                #smudge woz ere
1836                putserv "PRIVMSG $trivia_channel :$position[trivia_ordinal $position] place: [lindex $winner 0] with [lindex $winner 2] points"
1837                set sql "INSERT INTO winners VALUES ([lindex $winner 1], $now, [expr 6 - $position])"
1838                putloglev d * $sql
1839                trivia_db_handle eval $sql
1840
1841                set sql "UPDATE users SET user_score = user_score + [expr 6 - $position]"
1842                putloglev d * $sql
1843                trivia_db_handle eval $sql
1844
1845                incr position
1846        }
1847
1848        set sql "DELETE FROM scores"
1849        putloglev d * $sql
1850        trivia_db_handle eval $sql
1851}
1852
1853#>>>
1854
1855#get the timestamp for next cutoff
1856proc trivia_score_get_time { } {
1857#<<<
1858        global trivia_score_time
1859
1860        set trivia_score_time [clock scan "friday 19:00"]
1861        if {$trivia_score_time < [clock seconds]} {
1862                set trivia_score_time [clock scan "next friday 19:00"]
1863        }
1864        set trivia_score_time [expr $trivia_score_time]
1865        putloglev d * "setting next score rotation to [clock format $trivia_score_time]"
1866}
1867#>>>
1868
1869#figure out how long is left until the score rotation
1870proc trivia_score_time_left { } {
1871        #<<<
1872        global trivia_score_time
1873
1874        set now [clock seconds]
1875        if {$now > $trivia_score_time} {
1876                #erk
1877                putloglev d * "trivia_score_time_left: oops!"
1878                putloglev d * "now: $now, time: $trivia_score_time"
1879                putloglev d * [clock format $now]
1880                putloglev d * [clock format $trivia_score_time]
1881                return
1882        }
1883       
1884        set diff [expr $trivia_score_time - $now]
1885        putloglev d * "trivia_score_time_left: difference is $diff seconds"
1886
1887        if {$diff > 60} {
1888                return [trivia_time_to_words $diff]
1889        } else {
1890                return "less than a minute"
1891        }
1892}
1893#>>>
1894
1895proc trivia_time_to_words { time } {
1896#<<<
1897        putloglev 2 * "trivia_time_to_words $time"
1898        set output ""
1899
1900        if {$time > 86400} {
1901                set days [expr $time / 86400]
1902                append output $days
1903                append output " day"
1904                if {$days > 1} {
1905                        append output "s"
1906                }
1907                set time [expr $time - [expr $days * 86400]]
1908        append output " "
1909        }
1910
1911        if {$time > 3600} {
1912                set hours [expr $time / 3600]
1913                append output $hours
1914                append output " hour"
1915                if {$hours > 1} {
1916                        append output "s"
1917                }
1918                set time [expr $time - [expr $hours * 3600]]
1919        append output " "
1920        }
1921
1922        if {$time > 60} {
1923                set mins [expr $time / 60]
1924                append output $mins
1925                append output " minute"
1926                if {$mins > 1} {
1927                        append output "s"
1928                }
1929        }
1930
1931        set output [string trim $output]
1932        putloglev d * "trivia_time_to_words returing $output"
1933        return $output
1934}
1935#>>>
1936
1937proc trivia_score_rot_timer { } {
1938        global trivia_score_time trivia_channel trivia_c trivia_asking_question trivia_warned
1939
1940        #putloglev 1 * "score_rot tick"
1941        utimer 10 trivia_score_rot_timer
1942
1943        if {[clock seconds] > $trivia_score_time} {
1944                #end of week!
1945
1946                putlog "trivia: end of week"
1947
1948                if {$trivia_asking_question == 1} {
1949                        putlog "trivia: game is running"
1950                        if {$trivia_warned == 0} {
1951                                putlog "trivia: need to warn"
1952                                putquick "PRIVMSG $trivia_channel :$trivia_c(red)### BING BONG ###"
1953                                putquick "PRIVMSG $trivia_channel :I've started so I'll finish."
1954                                set trivia_warned 1
1955                        }
1956                        return 0
1957                } else {
1958                        putlog "trivia: not running game, ending week now"
1959                        trivia_end_week
1960                        return 0
1961                }
1962        }
1963        set trivia_warned 0
1964}
1965#>>>
1966
1967# handle end of week
1968proc trivia_end_week { } {
1969#<<<
1970        global trivia_channel trivia_score_time
1971
1972        # set next week end
1973        trivia_score_get_time
1974
1975        # move scores around
1976        trivia_score_winners
1977#>>>
1978}
1979
1980# Announce the time remaining
1981proc trivia_countdown { } {
1982#<<<
1983        global trivia_channel
1984
1985        putserv "PRIVMSG $trivia_channel :[trivia_score_time_left] left until end of this game."
1986}
1987#>>>
1988
1989trivia_connect
1990trivia_score_get_time
1991utimer 10 trivia_score_rot_timer
1992
1993putlog {TriviaEngine ENGAGED(*$£&($}
1994
1995if {$trivia_must_rehash == 2} {
1996  putlog "Auto-restarting trivia..."
1997        trivia_start
1998        set trivia_must_rehash 0
1999}
Note: See TracBrowser for help on using the repository browser.