import { Area , Location , Map , MapsCreatr , PreActor , PreActorLike , PreActorsContainers , PreActorSettings , } from "mapscreatr" ; import { MapScreenr } from "mapscreenr" ; import { AreaSpawnrSettings , CommandAdder } from "./types" ; /**
 * Directional equivalents for converting from directions to keys.
 */ const directionKeys = { xDec : "right" , xInc : "left" , yDec : "bottom" , yInc : "top" , } ; /**
 * Opposite directions for when finding descending order Arrays.
 */ const directionOpposites = { xDec : "xInc" , xInc : "xDec" , yDec : "yInc" , yInc : "yDec" , } ; param direction param top param right param bottom param left returns const getDirectionEnd = ( directionKey , top , right , bottom , left ) : number => { switch ( directionKey ) { case "top" : return top ; case "right" : return right ; case "bottom" : return bottom ; case "left" : return left ; default : throw new Error ( `Unknown directionKey: '${ directionKey }'.` ) ; } } ; param direction param group param _mid param top param right param bottom param left returns const findPreActorsSpawnStart = ( direction , group , top , right , bottom , left ) : number => { const directionKey = directionKeys [ direction ] ; const directionEnd = getDirectionEnd ( directionKey , top , right , bottom , left ) ; for ( let i = 0 ; i < group . length ; i += 1 ) { if ( ( group as any ) [ i ] [ directionKey ] >= directionEnd ) { return i ; } } return group . length ; } ; param direction param group param _mid param top param right param bottom param left returns const findPreActorsSpawnEnd = ( direction , group , top , right , bottom , left ) : number => { const directionKey = directionKeys [ direction ] ; const directionKeyOpposite = directionKeys [ directionOpposites [ direction ] ] ; const directionEnd = getDirectionEnd ( directionKeyOpposite , top , right , bottom , left ) ; for ( let i = group . length - 1 ; i >= 0 ; i -= 1 ) { if ( ( group [ i ] as any ) [ directionKey ] <= directionEnd ) { return i ; } } return - 1 ; } ; /**
 * Loads EightBittr maps to spawn and unspawn areas on demand.
 */ export class AreaSpawnr { /**
     * Storage container and lazy loader for EightBittr maps.
     */ private readonly mapsCreator : MapsCreatr ; /**
     * MapScreenr container for attributes copied from Areas.
     */ private readonly mapScreenr : MapScreenr ; /**
     * The names of attributes to be copied to the MapScreenr during setLocation.
     */ private readonly screenAttributes : string [ ] ; /**
     * Function for when a PreActor is to be spawned.
     */ private readonly onSpawn ? : ( preactor : PreActor ) => void ; /**
     * Function for when a PreActor is to be un-spawned.
     */ private readonly onUnspawn ? : ( preactor : PreActor ) => void ; /**
     * If stretches exists, a Function to add stretches to an Area.
     */ private readonly stretchAdd ? : CommandAdder ; /**
     * If afters exists, a Function to add afters to an Area.
     */ private readonly afterAdd ? : CommandAdder ; /**
     * The name of the currently referenced Map, set by setMap.
     */ private mapName : string ; /**
     * The currently referenced Map, set by setMap.
     */ private mapCurrent : Map ; /**
     * The currently referenced Area, set by setLocation.
     */ private areaCurrent : Area ; /**
     * The currently referenced Location, set by setLocation.
     */ private locationEntered : Location ; /**
     * The current Area's listing of PreActors.
     */ private preactors : PreActorsContainers ; param settings public constructor ( settings ) { this . mapsCreator = settings . mapsCreatr ; this . mapScreenr = settings . mapScreenr ; this . onSpawn = settings . onSpawn ; this . onUnspawn = settings . onUnspawn ; this . screenAttributes = settings . screenAttributes || [ ] ; this . stretchAdd = settings . stretchAdd ; this . afterAdd = settings . afterAdd ; } returns public getScreenAttributes ( ) { return this . screenAttributes ; } returns public getMapName ( ) { return this . mapName ; } param name returns public getMap ( name ? ) { return typeof name === "undefined" ? this . mapCurrent : this . mapsCreator . getMap ( name ) ; } returns public getMaps ( ) { return this . mapsCreator . getMaps ( ) ; } returns public getArea ( ) { return this . areaCurrent ; } returns public getAreaName ( ) { return this . areaCurrent . name ; } param location returns public getLocation ( location ) { return this . areaCurrent . map . locations [ location ] ; } returns public getLocationEntered ( ) { return this . locationEntered ; } returns public getPreActors ( ) { return this . preactors ; } param name param location returns public setMap ( name , location ? ) { this . mapCurrent = this . getMap ( name ) ; if ( ! this . mapCurrent ) { throw new Error ( `Unknown Map in setMap: '${ name }'.` ) ; } this . mapName = name ; if ( location !== undefined ) { this . setLocation ( location ) ; } return this . mapCurrent ; } param name returns public setLocation ( name ) { const location = this . mapCurrent . locations [ name ] ; if ( ! location ) { throw new Error ( `Unknown location in setLocation: '${ name }'.` ) ; } this . locationEntered = location ; this . areaCurrent = location . area ; this . areaCurrent . boundaries = { bottom : 0 , left : 0 , right : 0 , top : 0 , } ; for ( const attribute of this . screenAttributes ) { this . mapScreenr . variables [ attribute ] = ( this . areaCurrent as any ) [ attribute ] ; } this . preactors = this . mapsCreator . getPreActors ( location . area ) ; if ( this . areaCurrent . stretches ) { this . setStretches ( this . areaCurrent . stretches ) ; } if ( this . areaCurrent . afters ) { this . setAfters ( this . areaCurrent . afters ) ; } return location ; } param stretchesRaw public setStretches ( stretchesRaw ) { if ( ! this . stretchAdd ) { throw new Error ( "Cannot call setStretches without a stretchAdd." ) ; } for ( let i = 0 ; i < stretchesRaw . length ; i += 1 ) { this . stretchAdd ( stretchesRaw [ i ] , i , stretchesRaw ) ; } } param aftersRaw public setAfters ( aftersRaw ) { if ( ! this . afterAdd ) { throw new Error ( "Cannot call setAfters without an afterAdd." ) ; } for ( let i = 0 ; i < aftersRaw . length ; i += 1 ) { this . afterAdd ( aftersRaw [ i ] , i , aftersRaw ) ; } } param direction param top param right param bottom param left public spawnArea ( direction , top , right , bottom , left ) { if ( this . onSpawn ) { this . applySpawnAction ( this . onSpawn , true , direction , top , right , bottom , left ) ; } } param direction param top param right param bottom param left public unspawnArea ( direction , top , right , bottom , left ) { if ( this . onUnspawn ) { this . applySpawnAction ( this . onUnspawn , false , direction , top , right , bottom , left ) ; } } param callback param status param direction param top param right param bottom param left private applySpawnAction ( callback , status , direction , top , right , bottom , left ) { for ( const name in this . preactors ) { if ( ! { } . hasOwnProperty . call ( this . preactors , name ) ) { continue ; } const group = ( this . preactors as any ) [ name ] [ direction ] ; if ( group . length === 0 ) { continue ; } const start = findPreActorsSpawnStart ( direction , group , top , right , bottom , left ) ; const end = findPreActorsSpawnEnd ( direction , group , top , right , bottom , left ) ; for ( let i = start ; i <= end ; i += 1 ) { const preactor = group [ i ] ; if ( preactor . spawned !== status ) { preactor . spawned = status ; callback ( preactor ) ; } } } } }