import { DiscordAPIError , DiscordInteraction , DiscordMessage , DiscordMessageActionRow , DiscordMessageButton , DiscordMessageReactionAdd , DiscordUser , Snowflake , DiscordButtonStyle } from 'discord-minimal' ; import { GameContent } from './game-content' ; import GameResult , { ResultType } from './game-result' ; export default abstract class GameBase { protected gameId ! : number ; protected gameType : string ; protected isMultiplayerGame : boolean ; protected inGame = false ; protected result : GameResult | undefined = undefined ; protected gameMessage : DiscordMessage | undefined = undefined ; public gameStarter ! : DiscordUser ; public player2 : DiscordUser | null = null ; public player1Turn = true ; protected onGameEnd : ( result : GameResult ) => void = ( ) => { } ; protected gameTimeoutId : NodeJS . Timeout | undefined ; protected abstract getContent ( ) ; protected abstract getGameOverContent ( result ) ; public abstract onReaction ( reaction ) ; public abstract onInteraction ( interaction ) ; constructor ( gameType , isMultiplayerGame ) { this . gameType = gameType ; this . isMultiplayerGame = isMultiplayerGame ; } public newGame ( msg , player2 , onGameEnd ) { this . gameStarter = msg . author ; this . player2 = player2 ; this . onGameEnd = onGameEnd ; this . inGame = true ; const content = this . getContent ( ) ; msg . sendInChannel ( { embeds : content . embeds , components : content . components } ) . then ( emsg => { this . gameMessage = emsg ; this . gameTimeoutId = setTimeout ( ( ) => this . gameOver ( { result : ResultType . TIMEOUT } ) , 60000 ) ; } ) . catch ( e => this . handleError ( e , 'send message/ embed' ) ) ; } protected step ( edit = false ) { if ( edit ) this . gameMessage ?. edit ( this . getContent ( ) ) ; if ( this . gameTimeoutId ) clearTimeout ( this . gameTimeoutId ) ; this . gameTimeoutId = setTimeout ( ( ) => this . gameOver ( { result : ResultType . TIMEOUT } ) , 60000 ) ; } public handleError ( e , perm ) { if ( e instanceof DiscordAPIError ) { const de = e as DiscordAPIError ; switch ( de . code ) { case 10003 : this . gameOver ( { result : ResultType . ERROR , error : 'Channel not found!' } ) ; break ; case 10008 : this . gameOver ( { result : ResultType . DELETED , error : 'Message was deleted!' } ) ; break ; case 50001 : if ( this . gameMessage ) this . gameMessage . sendMessageInChannel ( 'The bot is missing access to preform some of it\'s actions!' ) . catch ( ( ) => { console . log ( 'Error in the access error handler!' ) ; } ) ; else console . log ( 'Error in the access error handler!' ) ; this . gameOver ( { result : ResultType . ERROR , error : 'Missing access!' } ) ; break ; case 50013 : if ( this . gameMessage ) this . gameMessage . sendMessageInChannel ( `The bot is missing the '${ perm }' permissions it needs order to work!` ) . catch ( ( ) => { console . log ( 'Error in the permission error handler!' ) ; } ) ; else console . log ( 'Error in the permission error handler!' ) ; this . gameOver ( { result : ResultType . ERROR , error : 'Missing permissions!' } ) ; break ; default : console . log ( 'Encountered a Discord error not handled! ' ) ; console . log ( e ) ; break ; } } else { this . gameOver ( { result : ResultType . ERROR , error : 'Game embed missing!' } ) ; } } public gameOver ( result , interaction = undefined ) { if ( ! this . inGame ) return ; this . result = result ; this . inGame = false ; const gameOverContent = this . getGameOverContent ( result ) ; if ( result . result !== ResultType . FORCE_END ) { this . onGameEnd ( result ) ; this . gameMessage ?. edit ( gameOverContent ) . catch ( e => this . handleError ( e , '' ) ) ; this . gameMessage ?. removeAllReactions ( ) ; } else { if ( interaction ) interaction . update ( gameOverContent ) ; else this . gameMessage ?. edit ( gameOverContent ) . catch ( e => this . handleError ( e , '' ) ) ; } if ( this . gameTimeoutId ) clearTimeout ( this . gameTimeoutId ) ; } protected getWinnerText ( result ) { if ( result . result === ResultType . TIE ) return 'It was a tie!' ; else if ( result . result === ResultType . TIMEOUT ) return 'The game went unfinished :(' ; else if ( result . result === ResultType . FORCE_END ) return 'The game was ended' ; else if ( result . result === ResultType . ERROR ) return 'ERROR: ' + result . error ; else if ( result . result === ResultType . WINNER ) return '`' + result . name + '` has won!' ; else if ( result . result === ResultType . LOSER ) return '`' + result . name + '` has lost!' ; return '' ; } public setGameId ( id ) { this . gameId = id ; } public getGameId ( ) { return this . gameId ; } public getGameType ( ) { return this . gameType ; } public getMessageId ( ) { return this . gameMessage ?. id ?? - 1 ; } public isInGame ( ) { return this . inGame ; } public doesSupportMultiplayer ( ) { return this . isMultiplayerGame ; } public createMessageActionRowButton ( buttonInfo ) { return new DiscordMessageActionRow ( ) . addComponents ( buttonInfo . map ( ( [ id , label ] ) => new DiscordMessageButton ( ) . setCustomId ( id ) . setLabel ( label ) . setStyle ( DiscordButtonStyle . Secondary ) ) ) ; } }