TriviaEngine-sqlite.tcl 43 KB

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