import { DefaultEntity } from './default-entity' ; import { Helper } from '../../helper' ; import { EnemyData } from '../../../../models/enemy' ; import { PathResolver , BasePath , FileExtension } from '../../../path-resolver' ; import { MultiDirAnimation } from '../../../../models/multi-dir-animation' ; import { MultiEntityAnimation } from '../../../../models/multi-entity-animation' ; import { TileSheet } from '../../../../models/tile-sheet' ; import { Point , Point3 } from '../../../../models/cross-code-map' ; import { SingleDirAnimation } from '../../../../models/single-dir-animation' ; export class Enemy extends DefaultEntity { protected async setupType ( settings ) { settings . enemyInfo = settings . enemyInfo || { } ; const enemyPath = PathResolver . convertToPath ( BasePath . ENEMIES , settings . enemyInfo . type || '' , FileExtension . NONE ) ; const enemyData = await Helper . getJsonPromise ( enemyPath ) as EnemyData | undefined ; if ( ! enemyData ) { this . generateErrorImage ( ) ; return ; } const sheetPath = PathResolver . convertToPath ( BasePath . ANIMATIONS , enemyData . anims , FileExtension . NONE ) ; const rawSheet = await Helper . getJsonPromise ( sheetPath ) ; if ( ! rawSheet ) { this . generateErrorImage ( ) ; return ; } const sheet = this . resolveSUB ( rawSheet ) as MultiDirAnimation [ ] | [ MultiEntityAnimation ] ; if ( ! sheet || sheet . length === 0 ) { this . generateErrorImage ( ) ; return ; } this . entitySettings . sheets = { fix : [ ] } ; if ( this . isMultiDir ( sheet ) ) { const anims = sheet . filter ( s => s . name === 'idle' ) ; if ( ! await this . renderMultiDirAnims ( anims . length > 0 ? anims : [ sheet [ 0 ] ] ) ) { this . generateErrorImage ( ) ; return ; } } else { if ( ! await this . renderMultiEntityAnim ( sheet [ 0 ] ) ) { this . generateErrorImage ( ) ; return ; } } this . entitySettings . baseSize = enemyData . size ; this . updateSettings ( ) ; } private resolveSUB ( object ) { if ( ! object . SUB || ! ( object . SUB instanceof Array ) ) { return [ object ] ; } const SUB = object . SUB ; const result = [ ] ; for ( const sub of SUB ) { for ( const subSub of this . resolveSUB ( sub ) ) { const combined = Object . assign ( Object . assign ( { } , subSub ) , object ) ; delete combined . SUB ; result . push ( combined ) ; } } return result ; } private isMultiDir ( sheet ) { return sheet [ 0 ] . DOCTYPE === 'MULTI_DIR_ANIMATION' ; } private async renderMultiDirAnims ( anims ) { const results = await Promise . all ( anims . map ( anim => this . renderMultiDirAnim ( anim ) ) ) ; return results . every ( r => r ) ; } private async renderMultiDirAnim ( anim ) { const tileSheet = typeof anim . sheet === 'string' ? anim . namedSheets [ anim . sheet ] : anim . sheet ; if ( ! await Helper . loadTexture ( tileSheet . src , this . scene ) ) { return false ; } const tileOffset = ( anim . dirs && anim . tileOffsets ) ? anim . tileOffsets [ Math . floor ( anim . dirs / 2 ) ] : 0 ; this . render ( tileSheet , { x : 0 , y : 0 } , anim . frames [ 0 ] + tileOffset ) ; return true ; } private render ( anim , pos , frame ) { const offsetX = ( anim . offX || 0 ) + ( anim . xCount ? ( frame % anim . xCount * anim . width ) : 0 ) ; const offsetY = ( anim . offY || 0 ) + ( anim . xCount ? ( Math . floor ( frame / anim . xCount ) * anim . height ) : 0 ) ; this . entitySettings . sheets . fix . push ( { gfx : anim . src . trim ( ) , h : anim . height , w : anim . width , x : offsetX , y : offsetY , offsetX : pos . x , offsetY : pos . y , } ) ; } private async renderMultiEntityAnim ( animation ) { const partAnims = { } ; const loading = [ ] ; if ( animation . namedSheets ) { for ( const sheet of Object . values ( animation . namedSheets ) ) { loading . push ( ( async ( name ) => { if ( ! await Helper . loadTexture ( name , this . scene ) ) { throw new Error ( 'Could not load texture: ' + name ) ; } } ) ( sheet . src ) ) ; } } for ( const [ partName , part ] of Object . entries ( animation . parts ) ) { partAnims [ partName ] = { } ; const partAnim = partAnims [ partName ] ; const anims = this . resolveSUB ( part . anims ) as SingleDirAnimation [ ] ; for ( const anim of anims ) { const entry = partAnim [ anim . name ] = partAnim [ anim . name ] || [ ] ; entry . push ( anim ) ; if ( typeof anim . sheet === 'object' ) { loading . push ( ( async ( name ) => { if ( ! await Helper . loadTexture ( name , this . scene ) ) { throw new Error ( 'Could not load texture: ' + name ) ; } } ) ( anim . sheet . src ) ) ; } else { anim . sheet = animation . namedSheets ! [ anim . sheet ] ; } } } const success = await Promise . all ( loading ) . then ( ( ) => true ) . catch ( ( ) => false ) ; if ( ! success ) { return false ; } const anim = animation . anims [ 'idle' ] || animation . anims [ 'default' ] || animation . anims [ Object . keys ( animation . anims ) [ 0 ] ] ; for ( const [ partName , partAnim ] of Object . entries ( anim . partAnims ) ) { const part = animation . parts [ partName ] ; const offset = { x : ( part . size . x - animation . baseSize . x ) / 2 , y : ( part . size . y - animation . baseSize . y ) / 2 , z : 0 , } ; offset . x += part . pos . x ; offset . y += part . pos . y ; offset . z += part . pos . z ; offset . x += partAnim . posFrames [ 0 ] ; offset . y += partAnim . posFrames [ 1 ] ; offset . z += partAnim . posFrames [ 2 ] ; for ( const entry of partAnims [ partName ] [ partAnim . anim ] ) { this . renderSingleDirAnim ( entry , this . toPoint ( offset ) , part . size ) ; } } return true ; } private renderSingleDirAnim ( anim , offset , size ) { if ( anim . framesSpriteOffset ) { offset . x += anim . framesSpriteOffset [ 0 ] ; offset . y += anim . framesSpriteOffset [ 1 ] - anim . framesSpriteOffset [ 2 ] ; } const sheet = anim . sheet as TileSheet ; offset . y += ( 1 - anim . wallY ) * ( size . y - sheet . height ) ; const offsetX = ( sheet . offX || 0 ) + ( sheet . xCount ? ( anim . frames [ 0 ] % sheet . xCount * sheet . width ) : 0 ) ; const offsetY = ( sheet . offY || 0 ) + ( sheet . xCount ? ( Math . floor ( anim . frames [ 0 ] / sheet . xCount ) * sheet . height ) : 0 ) ; this . entitySettings . sheets . fix . push ( { gfx : sheet . src . trim ( ) , h : sheet . height , w : sheet . width , x : offsetX , y : offsetY , offsetX : offset . x , offsetY : offset . y , flipX : anim . flipX , flipY : anim . flipY , } ) ; } private toPoint ( point3 ) { return { x : point3 . x , y : point3 . y - point3 . z , } ; } }