TriviaEngine-sqlite.tcl 42 KB

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