2021-11-06 00:33:52 +00:00
'use strict' ;
const config = require ( 'config' ) ;
const timers = require ( 'timers/promises' ) ;
const questions = require ( '../../assets/jeopardy.json' ) ;
2021-11-08 01:48:26 +00:00
const settings = { ... config . trivia } ;
2021-11-06 00:33:52 +00:00
let game = null ;
function shuffle ( unshuffledQuestions , limit = 10 ) {
const shuffled = unshuffledQuestions ;
for ( let i = shuffled . length - 1 ; i > 0 ; i -= 1 ) {
const j = Math . floor ( Math . random ( ) * ( i + 1 ) ) ;
const temp = shuffled [ i ] ;
shuffled [ i ] = shuffled [ j ] ;
shuffled [ j ] = temp ;
}
return shuffled . slice ( 0 , limit ) ;
}
function scoreRound ( context , round ) {
if ( game . answers . length === 0 ) {
return ` No one scored in round ${ round + 1 } , better luck next time! ` ;
}
return game . answers . map ( ( { user } ) => {
context . setPoints ( user , 1 ) ;
game . points [ user . username ] = ( game . points [ user . username ] || 0 ) + 1 ;
return ` **@ ${ user . username } ** gets a point ` ;
} ) . join ( ', ' ) ;
}
async function playRound ( context , round = 0 ) {
const ac = new AbortController ( ) ; // eslint-disable-line no-undef
const now = new Date ( ) ;
game . answers = [ ] ;
game . round = round ;
game . ac = ac ;
const question = game . questions [ round ] ;
context . sendMessage ( ` **Question ${ round + 1 } / ${ game . questions . length } **: ${ question . question } ` , context . room . id ) ;
context . logger . info ( ` Trivia asked " ${ question . question } " with answer: ${ question . answer } ` ) ;
try {
await timers . setTimeout ( game . timeout * 1000 , null , {
signal : ac . signal ,
} ) ;
} catch ( error ) {
// abort expected, not an error
}
if ( ! ac . signal . aborted ) {
ac . abort ( ) ;
}
if ( game . stopped ) {
context . sendMessage ( ` The game was stopped by ${ game . stopped . username } . The answer to the last question was: ** ${ question . answer } ** ` , context . room . id ) ;
game = null ;
return ;
}
if ( game . answers . length === 0 ) {
context . sendMessage ( ` **TIME'S UP!** No one guessed the answer: ** ${ question . answer } ** ` , context . room . id ) ;
} else {
const scores = scoreRound ( context , round ) ;
if ( game . mode === 'first' ) {
2021-11-06 01:14:33 +00:00
context . sendMessage ( ` ** ${ question . answer } ** is the right answer, played in ** ${ ( ( new Date ( ) - now ) / 1000 ) . toFixed ( 3 ) } s**! ${ scores } ` , context . room . id ) ;
2021-11-06 00:33:52 +00:00
}
if ( game . mode === 'timeout' ) {
context . sendMessage ( ` **STOP!** The correct answer is ** ${ question . answer } **. ${ scores } ` , context . room . id ) ;
}
}
if ( round < game . questions . length - 1 ) {
await timers . setTimeout ( 5000 ) ;
if ( game . stopped ) {
context . sendMessage ( ` The game was stopped by ${ game . stopped . username } ` , context . room . id ) ;
game = null ;
return ;
}
playRound ( context , round + 1 ) ;
return ;
}
2021-11-08 01:48:26 +00:00
await timers . setTimeout ( 2000 ) ;
2021-11-06 00:33:52 +00:00
const leaders = Object . entries ( game . points ) . sort ( ( [ , scoreA ] , [ , scoreB ] ) => scoreB - scoreA ) . map ( ( [ username , score ] , index ) => {
if ( index === 0 ) {
return ` **@ ${ username } ** with ** ${ score } ** points ` ;
}
return ` **@ ${ username } ** with ** ${ score } ** points ` ;
} ) . join ( ', ' ) ;
2021-11-08 01:48:26 +00:00
2021-11-06 00:33:52 +00:00
context . sendMessage ( ` That's the end of the game! Best players: ${ leaders } ` , context . room . id ) ;
game = null ;
}
async function start ( context ) {
const roundQuestions = shuffle ( questions , settings . rounds ) ;
game = {
round : 0 ,
questions : roundQuestions ,
answers : [ ] ,
points : { } ,
... settings ,
} ;
playRound ( context , 0 ) ;
}
async function stop ( context ) {
game . stopped = context . user ;
game . ac . abort ( ) ;
}
function onCommand ( args , context ) {
if ( ! context . subcommand && ! game ) {
start ( context ) ;
return ;
}
if ( ! context . subcommand && game ) {
context . sendMessage ( ` There is already a game going on! The current question for round ${ game . round + 1 } is: ${ game . questions [ game . round ] . question } ` , context . room . id ) ;
return ;
}
if ( context . subcommand === 'stop' && game ) {
stop ( context ) ;
}
if ( context . subcommand === 'stop' && ! game ) {
context . sendMessage ( ` There is no game going on at the moment. Start one with ${ config . prefix } trivia! ` , context . room . id ) ;
}
2021-11-09 12:48:21 +00:00
const subcommand = context . subcommand ? . toLowerCase ( ) ;
if ( subcommand ) {
settings [ subcommand ] = typeof settings [ subcommand ] === 'number' ? ( Number ( args [ 0 ] ) || settings [ subcommand ] ) : args [ 0 ] ;
context . sendMessage ( ` ${ subcommand } set to ${ settings [ subcommand ] } ` , context . room . id ) ;
}
2021-11-06 00:33:52 +00:00
}
async function onMessage ( message , context ) {
if ( ! game ) {
return ;
}
const { answer } = game . questions [ game . round ] ;
if ( new RegExp ( answer , 'i' ) . test ( message . body ) ) {
game . answers . push ( {
user : context . user ,
answer : message . body ,
} ) ;
if ( settings . mode === 'first' ) {
game . ac . abort ( ) ;
}
}
}
module . exports = {
name : 'Trivia' ,
onCommand ,
onMessage ,
} ;