import { AutoWired , Singleton , Inject } from 'typescript-ioc' ; import { DatabaseManager } from './database-manager' ; import { Festivals } from '../../../shared/models/entity' ; import { IFestival , Stat , Channel , FestivalChannelOperation } from '../../../shared/interfaces' ; import { RNGService } from './rng-service' ; import { Player } from '../../../shared/models' ; import { ChatHelper } from './chat-helper' ; import { SubscriptionManager } from './subscription-manager' ; import { PlayerManager } from './player-manager' ; @ Singleton @ AutoWired export class FestivalManager { @ Inject private db : DatabaseManager ; @ Inject private playerManager : PlayerManager ; @ Inject private subscriptionManager : SubscriptionManager ; @ Inject private chat : ChatHelper ; @ Inject private rng : RNGService ; private festivals : Festivals ; async init ( ) { this . festivals = await this . db . loadFestivals ( ) ; if ( ! this . festivals ) { this . festivals = new Festivals ( ) ; this . save ( ) ; } if ( this . festivals && this . festivals . festivals ) this . tick ( ) ; this . festivals . init ( ) ; this . subscribeToFestivalChanges ( ) ; } public tick ( ) { this . festivals . festivals . forEach ( festival => { if ( this . isValidFestival ( festival ) ) return ; this . initateRemoveFestival ( festival ) ; } ) ; } public getMultiplier ( stat ) { return this . festivals . festivals . reduce ( ( prev , cur ) => prev += cur . stats [ stat ] || 0 , 0 ) / 100 ; } public isValidFestival ( festival ) { return festival . endTime > Date . now ( ) ; } private makeSystemFestival ( festival ) { festival . startedBy = `☆${ festival . startedBy }` ; return festival ; } private getFestivalStatString ( festival ) { return Object . keys ( festival . stats ) . map ( x => `${ x . toUpperCase ( ) } ${ festival . stats [ x ] > 0 ? '+' : '' }${ festival . stats [ x ] }%` ) . join ( ', ' ) ; } public getFestivalDetails ( festival ) { const keys = { day : 86400 , hour : 3600 , minute : 60 , second : 1 } ; const milliseconds = festival . endTime - Date . now ( ) ; let duration = Math . floor ( ( milliseconds + 500 ) / 1000 ) ; const resp = { } ; const stamp = [ ] ; Object . keys ( keys ) . forEach ( function ( key ) { resp [ key ] = Math . floor ( duration / keys [ key ] ) ; duration -= resp [ key ] * keys [ key ] ; if ( resp [ key ] > 0 ) { stamp . push ( `${ resp [ key ] } ${ resp [ key ] === 1 ? key : key + 's' }` ) ; } } ) ; return `Stat Boosts: ${ this . getFestivalStatString ( festival ) }. It will last ${ stamp . join ( ', ' ) }.` ; } public startAscensionFestival ( player ) { const endTime = new Date ( ) ; endTime . setDate ( endTime . getDate ( ) + 3 ) ; const festival = this . makeSystemFestival ( { name : `${ player . name }'s ${ player . ascensionLevel }★ Ascension` , startedBy : player . name , endTime : endTime . getTime ( ) , stats : { [ Stat . XP ] : player . ascensionLevel , [ Stat . GOLD ] : player . ascensionLevel , [ Stat . SALVAGE ] : player . ascensionLevel } } ) ; this . initiateAddFestival ( festival ) ; this . chat . sendMessageFromClient ( { message : `A new festival "${ festival . name }" has started! ${ this . getFestivalDetails ( festival ) }` , playerName : '☆System' } ) ; } public startGMFestival ( player , festival ) { const addedFestival = this . makeSystemFestival ( festival ) ; this . initiateAddFestival ( addedFestival ) ; this . chat . sendMessageFromClient ( { message : `A new festival "${ addedFestival . name }" has started! ${ this . getFestivalDetails ( festival ) }` , playerName : `☆${ player . name }` } ) ; } public startFestival ( player , festival ) { this . initiateAddFestival ( festival ) ; this . chat . sendMessageFromClient ( { message : `A new festival "${ festival . name }" has started! ${ this . getFestivalDetails ( festival ) }` , playerName : '☆System' } ) ; } private subscribeToFestivalChanges ( ) { this . subscriptionManager . subscribeToChannel ( Channel . Festivals , ( { festival , operation } ) => { switch ( operation ) { case FestivalChannelOperation . Add : { this . addFestival ( festival ) ; break ; } case FestivalChannelOperation . Remove : { this . removeFestival ( festival ) ; break ; } } } ) ; } public hasFestivalForName ( name ) { return this . festivals . festivals . some ( fest => fest . startedBy === name ) ; } public hasFestivalWithName ( festival ) { return this . festivals . festivals . some ( fest => fest . name === festival ) ; } public initiateAddFestival ( festival ) { if ( ! festival . id ) festival . id = this . rng . id ( ) ; this . subscriptionManager . emitToChannel ( Channel . Festivals , { festival , operation : FestivalChannelOperation . Add } ) ; return true ; } public initateRemoveFestival ( festival ) { this . subscriptionManager . emitToChannel ( Channel . Festivals , { festival , operation : FestivalChannelOperation . Remove } ) ; } private addFestival ( festival ) { this . festivals . addFestival ( festival ) ; this . save ( ) ; this . playerManager . allPlayers . forEach ( player => player . recalculateStats ( ) ) ; } public removeFestival ( festival ) { this . festivals . removeFestival ( festival . id ) ; this . save ( ) ; this . playerManager . allPlayers . forEach ( player => player . recalculateStats ( ) ) ; } private save ( ) { this . db . saveFestivals ( this . festivals ) ; } }