import { WWA } from "./wwa_main" ; import { Position , Direction , WWAConsts as Consts , Status , EquipmentStatus , speedList , PartsType , ItemMode , SystemMessage2 , SystemSound , AppearanceTriggerType , Coord , DEVICE_TYPE , OS_TYPE } from "./wwa_data" ; import { Camera } from "./wwa_camera" ; import { Monster } from "./wwa_monster" ; import * as util from "./wwa_util" ; export class Parts { protected _position : Position ; protected _wwa : WWA ; public getPosition ( ) { return this . _position ; } constructor ( pos ) { this . _position = pos ; } } export class PartsObject extends Parts { constructor ( pos ) { super ( pos ) ; } } export class PartsMap extends Parts { constructor ( pos ) { super ( pos ) ; } } export enum PlayerState { CONTROLLABLE , MOVING , CAMERA_MOVING , MESSAGE_WAITING , LOCALGATE_JUMPED , BATTLE , ESTIMATE_WINDOW_WAITING , PASSWORD_WINDOW_WAITING , LOCALGATE_JUMPED_WITH_MESSAGE } export class Player extends PartsObject { protected _status : Status ; protected _equipStatus : EquipmentStatus ; protected _energyMax : number ; protected _dir : Direction ; protected _jumpWaitFramesRemain : number ; protected _camera : Camera ; protected _state : PlayerState ; protected _isPartsEventExecuted : boolean ; protected _samePosLastExecutedMapID : number ; protected _samePosLastExecutedObjID : number ; protected _executedObjPartsID_onSamePosition : number ; protected _isMovingImage : boolean ; protected _partsAppeared : boolean ; protected _energyValueElement : HTMLElement ; protected _strengthValueElement : HTMLElement ; protected _defenceValueElement : HTMLElement ; protected _goldValueElement : HTMLElement ; protected _itemBox : number [ ] ; protected _itemBoxElement : HTMLDivElement [ ] ; protected _itemUsingEvent : EventListener [ ] ; protected _readyToUseItemPos : number ; protected _isReadyToUseItem : boolean ; protected _battleFrameCounter : number ; protected _isPlayerTurn : boolean ; protected _battleTurnNum : number ; protected _enemy : Monster ; protected _moves : number ; protected _frameCount : number ; protected _moveMacroWaitingRemainMoves : number ; protected _moveObjectAutoExecTimer : number ; protected _afterMoveMacroFlag : boolean ; protected _isClickableItemGot : boolean ; protected _isPreparedForLookingAround : boolean ; protected _lookingAroundTimer : number ; protected _speedIndex : number ; protected _messageDelayFrameCount : number ; public move ( ) { if ( this . isControllable ( ) ) { this . controll ( this . _dir ) ; return ; } if ( this . _state === PlayerState . CAMERA_MOVING ) { try { this . _camera . move ( this . _dir ) ; } catch ( e ) { } if ( this . _isOnCameraStopPosition ( ) ) { this . _state = PlayerState . CONTROLLABLE ; } } else if ( this . _state === PlayerState . MOVING ) { try { var next = this . _position . getNextFramePosition ( this . _dir , speedList [ this . _speedIndex ] , speedList [ this . _speedIndex ] ) ; } catch ( e ) { } if ( next . isJustPosition ( ) ) { this . _state = PlayerState . CONTROLLABLE ; this . toggleMovingImage ( ) ; this . _moves ++ ; this . _isPartsEventExecuted = false ; this . _samePosLastExecutedMapID = void 0 ; this . _samePosLastExecutedObjID = void 0 ; } this . _position = next ; } } public controll ( moveDir ) { var nextFramePos ; var nextJustPos ; if ( this . isControllable ( ) ) { this . _isPreparedForLookingAround = false ; this . _dir = moveDir ; try { nextFramePos = this . _position . getNextFramePosition ( this . _dir , speedList [ this . _speedIndex ] , speedList [ this . _speedIndex ] ) ; nextJustPos = this . _position . getNextJustPosition ( moveDir ) ; } catch ( e ) { return ; } if ( this . _isOnCameraMovingPosition ( ) ) { if ( this . _wwa . getMapIdByPosition ( nextJustPos ) !== 0 || this . _wwa . isOldMap ( ) || this . _wwa . debug ) { try { this . _camera . move ( this . _dir ) ; this . _state = PlayerState . CAMERA_MOVING ; } catch ( e ) { this . _state = PlayerState . CONTROLLABLE ; } } return ; } if ( ! this . canMoveTo ( nextJustPos ) ) { if ( this . _wwa . getMapTypeByPosition ( nextJustPos ) === Consts . MAP_WALL ) { this . _wwa . checkMap ( nextJustPos . getPartsCoord ( ) ) ; } this . _wwa . checkObject ( nextJustPos . getPartsCoord ( ) ) ; return ; } this . _position = nextFramePos ; this . _state = PlayerState . MOVING ; if ( this . _wwa . getMapAttributeByPosition ( this . _position . getNextJustPosition ( moveDir ) , Consts . ATR_TYPE ) !== Consts . MAP_LOCALGATE ) { this . _wwa . moveObjects ( true ) ; } } } public setDir ( newDir ) { this . _isPreparedForLookingAround = false ; this . _dir = newDir ; } public canMoveTo ( pos ) { if ( pos === null ) { return false ; } if ( this . _wwa . debug ) { return true ; } var w = this . _wwa . getMapWidth ( ) ; var pc = pos . getPartsCoord ( ) ; var po = pos . getOffsetCoord ( ) ; if ( this . _wwa . getMapIdByPosition ( pos ) === 0 && ! this . _wwa . isOldMap ( ) ) { return false ; } if ( this . _wwa . getMapTypeByPosition ( pos ) === Consts . MAP_WALL ) { return false ; } if ( this . _wwa . getObjectIdByPosition ( pos ) === 0 ) { return true ; } if ( this . _wwa . getObjectTypeByPosition ( pos ) === Consts . OBJECT_NORMAL && this . _wwa . getObjectAttributeByPosition ( pos , Consts . ATR_MODE ) === Consts . PASSABLE_OBJECT ) { return true ; } if ( this . _wwa . getObjectTypeByPosition ( pos ) === Consts . OBJECT_DOOR && this . _wwa . getObjectAttributeByPosition ( pos , Consts . ATR_NUMBER ) === Consts . PASSABLE_OBJECT ) { if ( this . hasItem ( this . _wwa . getObjectAttributeByPosition ( pos , Consts . ATR_ITEM ) ) ) { return false ; } return true ; } return false ; } public isMoving ( ) { return this . _state == PlayerState . MOVING || this . _state == PlayerState . CAMERA_MOVING ; } private _isOnCameraMovingPosition ( ) { var camPos = this . _camera . getPosition ( ) . getPartsCoord ( ) ; var pPos = this . getPosition ( ) . getPartsCoord ( ) ; return ( ( pPos . x - camPos . x === Consts . H_PARTS_NUM_IN_WINDOW - 1 && this . _dir === Direction . RIGHT ) || ( pPos . x === camPos . x && this . _dir === Direction . LEFT ) || ( pPos . y - camPos . y === Consts . V_PARTS_NUM_IN_WINDOW - 1 && this . _dir === Direction . DOWN ) || ( pPos . y === camPos . y && this . _dir === Direction . UP ) ) ; } private _isOnCameraStopPosition ( ) { var camPos = this . _camera . getPosition ( ) . getPartsCoord ( ) ; var pPos = this . getPosition ( ) . getPartsCoord ( ) ; return ( ( pPos . x - camPos . x === Consts . H_PARTS_NUM_IN_WINDOW - 1 && this . _dir === Direction . LEFT ) || ( pPos . x === camPos . x && this . _dir === Direction . RIGHT ) || ( pPos . y - camPos . y === Consts . V_PARTS_NUM_IN_WINDOW - 1 && this . _dir === Direction . UP ) || ( pPos . y === camPos . y && this . _dir === Direction . DOWN ) ) ; } public isControllable ( ) { var isAfterMoveMacro = this . _afterMoveMacroFlag ; this . _afterMoveMacroFlag = false ; return ( this . _state === PlayerState . CONTROLLABLE && ! this . _partsAppeared && ( ( this . _wwa . getMapTypeByPosition ( this . _position ) !== Consts . MAP_LOCALGATE && this . _wwa . getMapTypeByPosition ( this . _position ) !== Consts . MAP_URLGATE ) || ! this . _wwa . isPrevFrameEventExecuted ( ) ) && this . _moveMacroWaitingRemainMoves === 0 && this . _moveObjectAutoExecTimer === 0 && ! isAfterMoveMacro && this . _wwa . canInput ( ) ) ; } public getCopyOfItemBox ( ) { return this . _itemBox . slice ( ) ; } public getDir ( ) { return this . _dir ; } public isMovingImage ( ) { return this . _isMovingImage ; } public toggleMovingImage ( ) { if ( this . _isMovingImage ) { this . _isMovingImage = false ; } else { this . _isMovingImage = true ; } } public getEnergyMax ( ) { return this . _energyMax ; } public isJumped ( ) { return this . _state === PlayerState . LOCALGATE_JUMPED || this . _state === PlayerState . LOCALGATE_JUMPED_WITH_MESSAGE ; } public setMessageWaiting ( ) { this . _state = PlayerState . MESSAGE_WAITING ; } public isWaitingMessage ( ) { return this . _state === PlayerState . MESSAGE_WAITING ; } public isDelayFrame ( ) { return this . _messageDelayFrameCount > 0 ; } public updateDelayFrame ( ) { this . _messageDelayFrameCount -- ; } public setDelayFrame ( ) { this . _messageDelayFrameCount = 1 ; } public clearMessageWaiting ( ) { if ( this . _state === PlayerState . MESSAGE_WAITING ) { this . _state = PlayerState . CONTROLLABLE ; this . _isPartsEventExecuted = true ; if ( this . _isPreparedForLookingAround ) { this . _lookingAroundTimer = Consts . PLAYER_LOOKING_AROUND_START_FRAME ; } } } public setEstimateWindowWating ( ) { this . _state = PlayerState . ESTIMATE_WINDOW_WAITING ; } public isWatingEstimateWindow ( ) { return this . _state === PlayerState . ESTIMATE_WINDOW_WAITING ; } public clearEstimateWindowWaiting ( ) { if ( this . _state === PlayerState . ESTIMATE_WINDOW_WAITING ) { this . _state = PlayerState . CONTROLLABLE ; } } public setPasswordWindowWating ( ) { this . _state = PlayerState . PASSWORD_WINDOW_WAITING ; } public isWaitingPasswordWindow ( ) { return this . _state === PlayerState . PASSWORD_WINDOW_WAITING ; } public clearPasswordWindowWaiting ( ) { if ( this . _state === PlayerState . PASSWORD_WINDOW_WAITING ) { this . _state = PlayerState . CONTROLLABLE ; } } public isPartsEventExecuted ( ) { return this . _isPartsEventExecuted ; } public resetEventExecutionInfo ( ) { this . _isPartsEventExecuted = false ; } public getLastExecPartsIDOnSamePosition ( type ) { return type === PartsType . MAP ? this . _samePosLastExecutedMapID : this . _samePosLastExecutedObjID ; } public setLastExecInfoOnSamePosition ( type , id ) { if ( type === PartsType . MAP ) { this . _samePosLastExecutedMapID = id ; } else { this . _samePosLastExecutedObjID = id ; } } public processAfterJump ( ) { if ( this . _state !== PlayerState . LOCALGATE_JUMPED && this . _state !== PlayerState . LOCALGATE_JUMPED_WITH_MESSAGE ) { return ; } if ( -- this . _jumpWaitFramesRemain === 0 ) { this . _state = this . _state === PlayerState . LOCALGATE_JUMPED ? PlayerState . CONTROLLABLE : PlayerState . MESSAGE_WAITING ; } } public jumpTo ( pos ) { var prevCameraPos = this . _camera . getPosition ( ) ; var prevPos = this . getPosition ( ) ; if ( this . _position . equals ( pos ) ) { return false ; } this . _position = pos ; if ( ! pos . isInCameraRange ( this . _camera , true ) ) { this . _camera . reset ( pos ) ; } this . _state = this . _state === PlayerState . MESSAGE_WAITING ? PlayerState . LOCALGATE_JUMPED_WITH_MESSAGE : PlayerState . LOCALGATE_JUMPED ; this . _jumpWaitFramesRemain = Consts . LOCALGATE_PLAYER_WAIT_FRAME ; this . _samePosLastExecutedMapID = void 0 ; this . _samePosLastExecutedObjID = void 0 ; if ( pos . hasLocalGate ( ) ) { this . _dir = Direction . DOWN ; } else if ( pos . getPartsCoord ( ) . y <= this . _wwa . getMapWidth ( ) - 2 && pos . getNextJustPosition ( Direction . DOWN ) . hasLocalGate ( ) ) { this . _dir = Direction . UP ; } else if ( pos . getPartsCoord ( ) . y >= 1 && pos . getNextJustPosition ( Direction . UP ) . hasLocalGate ( ) ) { this . _dir = Direction . DOWN ; } else if ( pos . getPartsCoord ( ) . x <= this . _wwa . getMapWidth ( ) - 2 && pos . getNextJustPosition ( Direction . RIGHT ) . hasLocalGate ( ) ) { this . _dir = Direction . LEFT ; } else if ( pos . getPartsCoord ( ) . x >= 1 && pos . getNextJustPosition ( Direction . LEFT ) . hasLocalGate ( ) ) { this . _dir = Direction . RIGHT ; } else { this . _dir = Direction . DOWN ; } if ( ! this . _camera . getPosition ( ) . equals ( prevCameraPos ) ) { this . _isPreparedForLookingAround = true ; this . _lookingAroundTimer = Consts . PLAYER_LOOKING_AROUND_START_FRAME ; } return true ; } public systemJumpTo ( pos ) { this . _position = pos ; this . _camera . reset ( pos ) ; this . _camera . resetPreviousPosition ( ) ; this . _state = PlayerState . LOCALGATE_JUMPED ; this . _jumpWaitFramesRemain = Consts . LOCALGATE_PLAYER_WAIT_FRAME ; this . _samePosLastExecutedMapID = void 0 ; this . _samePosLastExecutedObjID = void 0 ; this . _dir = Direction . DOWN ; this . _isPreparedForLookingAround = true ; this . _lookingAroundTimer = Consts . PLAYER_LOOKING_AROUND_START_FRAME ; } public addStatusAll ( s ) { this . _status . add ( s ) ; if ( this . isDead ( ) ) { this . _status . energy = 0 ; } if ( this . _energyMax !== 0 ) { this . _status . energy = Math . min ( this . _status . energy , this . _energyMax ) ; } this . updateStatusValueBox ( ) ; return this . _status ; } public setEnergyMax ( em ) { this . _energyMax = em ; if ( em !== 0 ) { this . _status . energy = Math . min ( this . _status . energy , this . _energyMax ) ; } this . updateStatusValueBox ( ) ; return em ; } public setEnergy ( e ) { this . _status . energy = e ; if ( this . isDead ( ) ) { this . _status . energy = 0 ; } if ( this . _energyMax !== 0 ) { this . _status . energy = Math . min ( this . _status . energy , this . _energyMax ) ; } this . updateStatusValueBox ( ) ; return e ; } public damage ( amount ) { this . _status . energy = Math . max ( 0 , this . _status . energy - amount ) ; if ( this . isDead ( ) ) { this . _status . energy = 0 ; } if ( this . _energyMax !== 0 ) { this . _status . energy = Math . min ( this . _status . energy , this . _energyMax ) ; } this . updateStatusValueBox ( ) ; } public setStrength ( s ) { this . _status . strength = s ; this . updateStatusValueBox ( ) ; return s ; } public setDefence ( d ) { this . _status . defence = d ; this . updateStatusValueBox ( ) ; return d ; } public setGold ( g ) { this . _status . gold = g ; this . updateStatusValueBox ( ) ; return g ; } public getStatus ( ) { return this . _status . plus ( this . _equipStatus ) ; } public getStatusWithoutEquipments ( ) { return this . _status . plus ( new EquipmentStatus ( 0 , 0 ) ) ; } public getStatusOfEquipments ( ) { return this . _equipStatus . plus ( new EquipmentStatus ( 0 , 0 ) ) ; } public updateStatusValueBox ( ) { const totalStatus = this . _status . plus ( this . _equipStatus ) ; this . _energyValueElement . textContent = this . _wwa . isVisibleStatus ( "energy" ) ? String ( totalStatus . energy ) : "" ; this . _strengthValueElement . textContent = this . _wwa . isVisibleStatus ( "strength" ) ? String ( totalStatus . strength ) : "" ; this . _defenceValueElement . textContent = this . _wwa . isVisibleStatus ( "defence" ) ? String ( totalStatus . defence ) : "" ; this . _goldValueElement . textContent = this . _wwa . isVisibleStatus ( "gold" ) ? String ( totalStatus . gold ) : "" ; this . _wwa . _messageWindow ?. update ( ) ; this . _wwa . updateScore ( ) ; } readonly itemTransitioningClassName = "item-transitioning" ; readonly overwittenItemClassName = "item-overwritten" ; readonly overwittenItemSelector = `.${ this . overwittenItemClassName }` ; /**
     * アイテムエフェクト開始の setTimeout のタイマーを保持する配列
     * 添字はアイテムボックス位置 (0-11)
     */ readonly itemEffectStartTimers : ( number | undefined ) [ ] = new Array ( Consts . ITEMBOX_SIZE ) ; param animationOption public updateItemBox ( animationOption ? ) { for ( let i = 0 ; i < this . _itemBoxElement . length ; i ++ ) { const targetItemBoxElement = this . _itemBoxElement [ i ] ; const parentElement = util . $qs ( "#item" + i ) as HTMLDivElement ; if ( this . _itemBox [ i ] === 0 ) { targetItemBoxElement . style . backgroundPosition = "-40px 0px" ; this . disposeItemEffect ( i , this . _itemBoxElement [ i ] , parentElement ) ; continue ; } const cx = this . _wwa . getObjectCropXById ( this . _itemBox [ i ] ) ; const cy = this . _wwa . getObjectCropYById ( this . _itemBox [ i ] ) ; if ( ! animationOption || i !== animationOption . insertPos - 1 ) { targetItemBoxElement . style . backgroundPosition = "-" + cx + "px -" + cy + "px" ; this . disposeItemEffect ( i , this . _itemBoxElement [ i ] , parentElement ) ; continue ; } const dx = animationOption . itemScreenPixelCoord . x - animationOption . itemBoxScreenPixelCoord . x ; const dy = animationOption . itemScreenPixelCoord . y - animationOption . itemBoxScreenPixelCoord . y ; const durationMs = ( - dx ) * Consts . DEFAULT_FRAME_INTERVAL / Consts . ITEM_EFFECT_SPEED_PIXEL_PER_FRAME ; const useBlank = animationOption . overwrittenObjectId === 0 || animationOption . overwrittenObjectId === undefined ; const overwrittenCx = useBlank ? animationOption . itemBoxBackgroundImageCoord . x : this . _wwa . getObjectCropXById ( animationOption . overwrittenObjectId ) ; const overwrittenCy = useBlank ? animationOption . itemBoxBackgroundImageCoord . y : this . _wwa . getObjectCropYById ( animationOption . overwrittenObjectId ) ; targetItemBoxElement . style . left = dx + "px" ; targetItemBoxElement . style . top = dy + "px" ; if ( typeof this . itemEffectStartTimers [ i ] === "number" ) { clearInterval ( this . itemEffectStartTimers [ i ] ) ; } this . itemEffectStartTimers [ i ] = window . setTimeout ( ( ) => { this . itemEffectStartTimers [ i ] = undefined ; this . startItemEffect ( i , targetItemBoxElement , parentElement , { target : { x : cx , y : cy } , overwritten : { x : overwrittenCx , y : overwrittenCy } , } , durationMs ) ; } , Consts . DEFAULT_FRAME_INTERVAL ) ; } } param index param targetItemBoxElement param parentElement param crops param durationMs private startItemEffect ( index , targetItemBoxElement , parentElement , crops , durationMs ) { const prevOverwrittenItemElement = parentElement . querySelector ( this . overwittenItemSelector ) ; if ( prevOverwrittenItemElement ) { parentElement . removeChild ( prevOverwrittenItemElement ) ; } const overwrittenItemElement = document . createElement ( "div" ) ; overwrittenItemElement . classList . add ( this . overwittenItemClassName ) ; overwrittenItemElement . style . backgroundPosition = "-" + crops . overwritten . x + "px -" + crops . overwritten . y + "px" ; overwrittenItemElement . style . backgroundImage = parentElement . style . backgroundImage ; parentElement . appendChild ( overwrittenItemElement ) ; targetItemBoxElement . style . backgroundPosition = "-" + crops . target . x + "px -" + crops . target . y + "px" ; targetItemBoxElement . style . transitionDuration = durationMs + "ms" ; targetItemBoxElement . style . transitionProperty = "left,top" ; targetItemBoxElement . style . transitionTimingFunction = "linear" ; targetItemBoxElement . style . left = "0" ; targetItemBoxElement . style . top = "0" ; parentElement . classList . add ( this . itemTransitioningClassName ) ; targetItemBoxElement . addEventListener ( "transitionend" , ( ) => { this . disposeItemEffect ( index , targetItemBoxElement , parentElement ) ; } , { once : true } ) ; } param index param itemBoxElement param parentElement private disposeItemEffect ( index , itemBoxElement , parentElement ) { if ( typeof this . itemEffectStartTimers [ index ] === "number" ) { clearInterval ( this . itemEffectStartTimers [ index ] ) ; this . itemEffectStartTimers [ index ] = undefined ; } itemBoxElement . style . transitionDuration = "0s" ; itemBoxElement . style . transitionProperty = "" ; itemBoxElement . style . left = "0" ; itemBoxElement . style . top = "0" ; if ( parentElement . classList . contains ( this . itemTransitioningClassName ) ) { parentElement . classList . remove ( this . itemTransitioningClassName ) ; } const overwrittenItemElement = parentElement . querySelector ( this . overwittenItemSelector ) ; if ( overwrittenItemElement ) { parentElement . removeChild ( overwrittenItemElement ) ; } } public isDead ( ) { return this . _status . energy <= 0 ; } param objID param itemPos param isOverwrite param animationOption public addItem ( objID , itemPos = 0 , isOverwrite = false , animationOption ? ) { var insertPos ; var oldInsertPos ; var oldObjID ; var itemPos_partsData = this . _wwa . getObjectAttributeById ( objID , Consts . ATR_NUMBER ) ; var overwrittenObjectId = 0 ; if ( itemPos === 0 && itemPos_partsData !== 0 ) { itemPos = itemPos_partsData ; } if ( itemPos === 0 ) { if ( objID === 0 ) { return ; } insertPos = this . _getBlankItemPos ( ) ; if ( insertPos === Consts . ITEMBOX_IS_FULL ) { throw new Error ( "これ以上、アイテムを持てません。" ) ; } overwrittenObjectId = this . _itemBox [ insertPos - 1 ] ; this . _forceSetItemBox ( insertPos , objID ) ; } else if ( isOverwrite === false ) { insertPos = itemPos ; oldObjID = this . _itemBox [ insertPos - 1 ] ; if ( this . _wwa . getObjectAttributeById ( oldObjID , Consts . ATR_NUMBER ) !== this . _wwa . getObjectAttributeById ( objID , Consts . ATR_NUMBER ) ) { oldInsertPos = this . _getBlankItemPos ( ) ; if ( oldInsertPos !== Consts . ITEMBOX_IS_FULL ) { this . _forceSetItemBox ( oldInsertPos , oldObjID ) ; this . _forceSetItemBox ( insertPos , objID ) ; } else { throw new Error ( "これ以上、アイテムを持てません。" ) ; } } else { overwrittenObjectId = this . _itemBox [ insertPos - 1 ] ; this . _forceSetItemBox ( insertPos , objID ) ; } } else { insertPos = itemPos ; overwrittenObjectId = this . _itemBox [ insertPos - 1 ] ; this . _forceSetItemBox ( insertPos , objID ) ; } this . _updateEquipmentStatus ( ) ; this . updateItemBox ( animationOption ? { insertPos , itemScreenPixelCoord : animationOption . screenPixelCoord , itemBoxBackgroundImageCoord : animationOption . itemBoxBackgroundImageCoord , itemBoxScreenPixelCoord : new Coord ( Consts . MAP_WINDOW_WIDTH + ( insertPos - 1 ) % 3 * Consts . CHIP_SIZE , Consts . ITEMBOX_TOP_Y + Math . floor ( ( insertPos - 1 ) / 3 ) * Consts . CHIP_SIZE ) , overwrittenObjectId } : undefined ) ; } private _forceSetItemBox ( pos , id ) { var self = this ; var border = util . $qsh ( "#item" + ( pos - 1 ) + ">.item-click-border" ) ; var itemType = this . _wwa . getObjectAttributeById ( id , Consts . ATR_MODE ) ; this . removeItemByItemPosition ( pos ) ; this . _itemBox [ pos - 1 ] = id ; if ( id !== 0 && itemType !== ItemMode . NORMAL ) { var mes = this . _wwa . getSystemMessageById ( SystemMessage2 . CLICKABLE_ITEM ) ; if ( ! this . _isClickableItemGot ) { if ( mes !== "BLANK" ) { var deviceMessage = "" ; switch ( this . _wwa . userDevice . device ) { case DEVICE_TYPE . PC : deviceMessage = "このアイテムは右のボックスを選択することで使用できます。\n" + "使用できるアイテムは色枠で囲まれます。" ; break ; case DEVICE_TYPE . VR : deviceMessage = "このアイテムは右のボックスをクリックすることで使用できます。\n" + "使用できるアイテムは色枠で囲まれます。" ; break ; case DEVICE_TYPE . SP : deviceMessage = "このアイテムは右のボックスをタップすることで使用できます。\n" + "使用できるアイテムは色枠で囲まれます。" ; break ; case DEVICE_TYPE . GAME : switch ( this . _wwa . userDevice . os ) { case OS_TYPE . NINTENDO : deviceMessage = "このアイテムはＸボタンを押すか、右のボックスをタップすることで使用できます。\n" + "使用できるアイテムは色枠で囲まれます。" ; break ; case OS_TYPE . PLAY_STATION : deviceMessage = "このアイテムは△ボタンを押すことで使用できます。\n" + "使用できるアイテムは色枠で囲まれます。" ; break ; case OS_TYPE . XBOX : deviceMessage = "このアイテムはＹボタンを押すことで使用できます。\n" + "使用できるアイテムは色枠で囲まれます。" ; break ; } break ; } this . _wwa . setMessageQueue ( mes === "" ? deviceMessage : mes , false , true ) ; } this . _isClickableItemGot = true ; } border . style . display = "block" ; ( ( pos ) : void => { self . _itemUsingEvent [ pos - 1 ] = ( ) => { if ( self . isControllable ( ) || ( self . _wwa . _messageWindow . isItemMenuChoice ( ) ) ) { self . _wwa . _itemMenu . close ( ) ; self . _wwa . _setNextMessage ( ) ; self . _wwa . onselectitem ( pos ) ; } } ; } ) ( pos ) ; border . addEventListener ( "click" , this . _itemUsingEvent [ pos - 1 ] ) ; } } private _getBlankItemPos ( ) { var insertPos ; for ( insertPos = 1 ; insertPos < this . _itemBox . length + 1 ; insertPos ++ ) { if ( this . _itemBox [ insertPos - 1 ] === 0 ) { return insertPos ; } } return Consts . ITEMBOX_IS_FULL ; } private _updateEquipmentStatus ( ) { var i ; var newStatus = new EquipmentStatus ( 0 , 0 ) ; for ( i = 0 ; i < Consts . ITEMBOX_SIZE ; i ++ ) { if ( this . _itemBox [ i ] !== 0 ) { newStatus . strength += this . _wwa . getObjectAttributeById ( this . _itemBox [ i ] , Consts . ATR_STRENGTH ) ; newStatus . defence += this . _wwa . getObjectAttributeById ( this . _itemBox [ i ] , Consts . ATR_DEFENCE ) ; } } var diff = newStatus . minus ( this . _equipStatus ) ; this . _wwa . setStatusChangedEffect ( diff ) ; this . _equipStatus = newStatus ; this . updateStatusValueBox ( ) ; } public hasItem ( partsID ) { for ( var i = 0 ; i < Consts . ITEMBOX_SIZE ; i ++ ) { if ( this . _itemBox [ i ] === partsID ) { return true ; } } return false ; } public canUseItem ( itemPos ) { var partsID = this . _itemBox [ itemPos - 1 ] ; if ( partsID === 0 ) { return false ; } if ( this . _wwa . getObjectAttributeById ( partsID , Consts . ATR_MODE ) === ItemMode . NORMAL ) { return false ; } return true ; } public useItem ( ) { var itemID ; var messageID ; itemID = this . _itemBox [ this . _readyToUseItemPos - 1 ] ; if ( this . _wwa . getObjectAttributeById ( itemID , Consts . ATR_MODE ) !== ItemMode . NOT_DISAPPEAR ) { this . removeItemByItemPosition ( this . _readyToUseItemPos ) ; } var bg = < HTMLDivElement > ( util . $id ( "item" + ( this . _readyToUseItemPos - 1 ) ) ) ; setTimeout ( ( ) : void => { if ( bg . classList . contains ( "onpress" ) ) { bg . classList . remove ( "onpress" ) ; } } , Consts . DEFAULT_FRAME_INTERVAL ) ; this . _isReadyToUseItem = false ; this . _readyToUseItemPos = void 0 ; return itemID ; } public canHaveMoreItems ( ) { return this . _getBlankItemPos ( ) !== Consts . ITEMBOX_IS_FULL ; } public removeItemByItemPosition ( itemPos ) { var border ; if ( this . _itemBox [ itemPos - 1 ] === 0 ) { return ; } if ( this . _wwa . getObjectAttributeById ( this . _itemBox [ itemPos - 1 ] , Consts . ATR_MODE ) !== ItemMode . NORMAL ) { border = util . $qsh ( "#item" + ( itemPos - 1 ) + ">.item-click-border" ) ; border . removeEventListener ( "click" , this . _itemUsingEvent [ itemPos - 1 ] ) ; border . style . display = "none" ; } this . _itemBox [ itemPos - 1 ] = 0 ; this . _updateEquipmentStatus ( ) ; this . updateItemBox ( ) ; } public removeItemByPartsID ( partsID ) { var border ; if ( ! this . hasItem ( partsID ) ) { throw new Error ( "アイテムを持っていない" ) ; } for ( var i = 0 ; i < Consts . ITEMBOX_SIZE ; i ++ ) { if ( this . _itemBox [ i ] === partsID ) { if ( this . _wwa . getObjectAttributeById ( this . _itemBox [ i ] , Consts . ATR_MODE ) !== ItemMode . NORMAL ) { border = util . $qsh ( "#item" + i + ">.item-click-border" ) ; border . removeEventListener ( "click" , this . _itemUsingEvent [ i ] ) ; border . style . display = "none" ; } this . _itemBox [ i ] = 0 ; this . _updateEquipmentStatus ( ) ; this . updateItemBox ( ) ; return ; } } } public clearItemBox ( ) { for ( var i = 1 ; i <= Consts . ITEMBOX_SIZE ; i ++ ) { this . removeItemByItemPosition ( i ) ; } this . _updateEquipmentStatus ( ) ; this . updateItemBox ( ) ; } public hasGold ( gold ) { return this . _status . gold >= gold ; } public payGold ( gold ) { if ( ! this . hasGold ( gold ) ) { throw new Error ( "お金が足りない" ) ; } this . setGold ( this . _status . gold - gold ) ; } public earnGold ( gold ) { this . setGold ( this . _status . gold + gold ) ; } public setPartsAppearedFlag ( ) { this . _partsAppeared = true ; } public clearPartsAppearedFlag ( ) { this . _partsAppeared = false ; } public isPartsAppearedTime ( ) { return this . _partsAppeared === true ; } public startBattleWith ( enemy ) { this . _isPlayerTurn = true ; this . _battleFrameCounter = Consts . BATTLE_INTERVAL_FRAME_NUM ; this . _battleTurnNum = 0 ; this . _enemy = enemy ; this . _state = PlayerState . BATTLE ; } public isFighting ( ) { return this . _state === PlayerState . BATTLE ; } public isTurn ( ) { return this . _isPlayerTurn ; } public getTurnNum ( ) { return this . _battleTurnNum ; } public isBattleStartFrame ( ) { return this . _battleFrameCounter === Consts . BATTLE_INTERVAL_FRAME_NUM && this . _battleTurnNum === 0 ; } public fight ( ) { if ( ! this . isFighting ( ) ) { throw new Error ( "バトルが開始されていません。" ) ; } if ( this . _battleTurnNum === 0 && this . _battleFrameCounter === Consts . BATTLE_INTERVAL_FRAME_NUM ) { this . _wwa . showMonsterWindow ( ) ; } if ( -- this . _battleFrameCounter > 0 ) { return ; } this . _battleTurnNum ++ ; if ( this . _wwa . isBattleSpeedIndexForQuickBattle ( this . _speedIndex ) || this . _battleTurnNum > Consts . BATTLE_SPEED_CHANGE_TURN_NUM ) { if ( this . _battleTurnNum === 1 ) { this . _wwa . playSound ( SystemSound . ATTACK ) ; this . _wwa . vibration ( false ) ; } this . _battleFrameCounter = 1 ; } else { this . _battleFrameCounter = Consts . BATTLE_INTERVAL_FRAME_NUM ; this . _wwa . playSound ( SystemSound . ATTACK ) ; this . _wwa . vibration ( true ) ; } var playerStatus = this . getStatus ( ) ; var enemyStatus = this . _enemy . status ; if ( this . _isPlayerTurn ) { if ( playerStatus . strength > enemyStatus . defence || playerStatus . defence < enemyStatus . strength ) { if ( enemyStatus . energy > playerStatus . strength - enemyStatus . defence ) { if ( playerStatus . strength > enemyStatus . defence ) { this . _enemy . damage ( playerStatus . strength - enemyStatus . defence ) ; } } else { this . _wwa . playSound ( this . _wwa . getObjectAttributeById ( this . _enemy . partsID , Consts . ATR_SOUND ) ) ; this . earnGold ( enemyStatus . gold ) ; this . _wwa . setStatusChangedEffect ( new Status ( 0 , 0 , 0 , enemyStatus . gold ) ) ; if ( this . _enemy . item !== 0 ) { this . _wwa . setPartsOnPosition ( PartsType . OBJECT , this . _enemy . item , this . _enemy . position ) ; } else { this . _wwa . setPartsOnPosition ( PartsType . OBJECT , 0 , this . _enemy . position ) ; } this . _wwa . appearParts ( this . _enemy . position , AppearanceTriggerType . OBJECT , this . _enemy . partsID ) ; this . _state = PlayerState . CONTROLLABLE ; this . _wwa . setMessageQueue ( this . _enemy . message , false , false , this . _enemy . partsID , PartsType . OBJECT , this . _enemy . position ) ; this . _enemy . battleEndProcess ( ) ; this . _battleTurnNum = 0 ; this . _enemy = null ; } this . _isPlayerTurn = false ; return ; } this . _enemy . battleEndProcess ( ) ; this . _wwa . setMessageQueue ( "相手の防御能力が高すぎる！" , false , true ) ; this . _battleTurnNum = 0 ; this . _enemy = null ; } else { if ( enemyStatus . strength > playerStatus . defence ) { if ( playerStatus . energy > enemyStatus . strength - playerStatus . defence ) { this . damage ( enemyStatus . strength - playerStatus . defence ) ; } else { this . setEnergy ( 0 ) ; this . _enemy . battleEndProcess ( ) ; this . _state = PlayerState . CONTROLLABLE ; this . _battleTurnNum = 0 ; this . _enemy = null ; this . _wwa . gameover ( ) ; } } } this . _isPlayerTurn = true ; } public readyToUseItem ( itemPos ) { var itemID ; var messageID ; if ( ! this . canUseItem ( itemPos ) ) { throw new Error ( "アイテムがないか、アイテムが使えません。" ) ; } itemID = this . _itemBox [ itemPos - 1 ] ; messageID = this . _wwa . getObjectAttributeById ( itemID , Consts . ATR_STRING ) ; this . _wwa . appearParts ( this . _position . getPartsCoord ( ) , AppearanceTriggerType . OBJECT , itemID ) ; this . _readyToUseItemPos = itemPos ; this . _isReadyToUseItem = true ; } public isReadyToUseItem ( ) { return this . _isReadyToUseItem ; } public getDrawingCenterPosition ( ) { var pos = this . _position . getPartsCoord ( ) ; var poso = this . _position . getOffsetCoord ( ) ; var cameraPos = this . _camera . getPosition ( ) ; var cpParts = cameraPos . getPartsCoord ( ) ; var cpOffset = cameraPos . getOffsetCoord ( ) ; var targetX = ( pos . x - cpParts . x ) * Consts . CHIP_SIZE + poso . x - cpOffset . x + Consts . CHIP_SIZE / 2 ; var targetY = ( pos . y - cpParts . y ) * Consts . CHIP_SIZE + poso . y - cpOffset . y + Consts . CHIP_SIZE / 2 ; return new Coord ( targetX , targetY ) ; } /**
     * ゲーム開始から経過したフレーム数を基に、 HHHH:MM:SS 形式のプレイ時間文字列を返します。
     */ public getPlayTimeText ( ) { const seconds = Math . floor ( this . _frameCount / 60 ) ; return seconds >= 60 * 60 * 10000 ? "9999:99:99" : ( "000" + ( ( seconds / 60 / 60 ) | 0 ) ) . slice ( - 4 ) + ":" + ( "0" + ( ( ( seconds / 60 ) | 0 ) % 60 ) ) . slice ( - 2 ) + ":" + ( "0" + ( seconds % 60 ) ) . slice ( - 2 ) ; } public mainFrameCount ( ) { this . _frameCount ++ ; } public getFrameCount ( ) { return this . _frameCount ; } public setFrameCount ( count ) { if ( typeof count !== "number" ) { count = 0 ; } return this . _frameCount = count ; } public getMoveCount ( ) { return this . _moves ; } public setMoveCount ( count ) { return this . _moves = count ; } public isMoveObjectAutoExecTime ( ) { return this . _moveObjectAutoExecTimer === 0 ; } public setMoveMacroWaiting ( moveNum ) { if ( moveNum < 0 ) { return ; } this . _moveMacroWaitingRemainMoves = moveNum ; this . _moveObjectAutoExecTimer = 0 ; } public resetMoveObjectAutoExecTimer ( ) { this . _moveObjectAutoExecTimer = Consts . CHIP_SIZE / speedList [ this . _speedIndex ] ; this . _moveMacroWaitingRemainMoves -- ; } public decrementMoveObjectAutoExecTimer ( ) { if ( this . _moveMacroWaitingRemainMoves >= 0 && this . _moveObjectAutoExecTimer > 0 ) { this . _moveObjectAutoExecTimer -- ; if ( this . _moveMacroWaitingRemainMoves === 0 && this . _moveObjectAutoExecTimer === 0 ) { this . _afterMoveMacroFlag = true ; } } return 0 ; } public isWaitingMoveMacro ( ) { return this . _moveMacroWaitingRemainMoves !== 0 || this . _moveObjectAutoExecTimer !== 0 ; } public decrementLookingAroundTimer ( ) { if ( this . _isPreparedForLookingAround && this . _lookingAroundTimer > 0 ) { return -- this . _lookingAroundTimer ; } return 0 ; } public isLookingAround ( ) { return this . _isPreparedForLookingAround && this . _lookingAroundTimer === 0 ; } public getSpeedIndex ( ) { return this . _speedIndex ; } public speedUp ( ) { return this . _speedIndex = Math . min ( Consts . MAX_SPEED_INDEX , this . _speedIndex + 1 ) ; } public speedDown ( ) { return this . _speedIndex = Math . max ( Consts . MIN_SPEED_INDEX , this . _speedIndex - 1 ) ; } public setSpeedIndex ( speedIndex ) { if ( speedIndex < Consts . MIN_SPEED_INDEX || Consts . MAX_SPEED_INDEX < speedIndex ) { throw new Error ( "#set_speed の引数が異常です:" + speedIndex ) ; } this . _speedIndex = speedIndex ; return this . _speedIndex ; } constructor ( wwa , pos , camera , status , em , moves , gameSpeedIndex ) { super ( pos ) ; this . _status = status ; this . _equipStatus = new EquipmentStatus ( 0 , 0 ) ; this . _itemBox = new Array ( Consts . ITEMBOX_SIZE ) ; this . _itemBoxElement = new Array ( Consts . ITEMBOX_SIZE ) ; this . _itemUsingEvent = new Array ( Consts . ITEMBOX_SIZE ) ; for ( var i = 0 ; i < this . _itemBox . length ; i ++ ) { this . _itemBox [ i ] = 0 ; this . _itemBoxElement [ i ] = util . $qsh ( "#item" + i + ">.item-disp" ) as HTMLDivElement ; } this . updateItemBox ( ) ; this . _energyMax = em ; this . _dir = Direction . DOWN ; this . _isMovingImage = false ; this . _wwa = wwa ; this . _state = PlayerState . CONTROLLABLE ; this . _camera = camera ; this . _isPartsEventExecuted = false ; this . _energyValueElement = util . $qsh ( "#disp-energy>.status-value-box" ) ; this . _strengthValueElement = util . $qsh ( "#disp-strength>.status-value-box" ) ; this . _defenceValueElement = util . $qsh ( "#disp-defence>.status-value-box" ) ; this . _goldValueElement = util . $qsh ( "#disp-gold>.status-value-box" ) ; this . _isReadyToUseItem = false ; this . _isClickableItemGot = false ; this . _moves = moves ; this . _frameCount = 0 ; this . _moveMacroWaitingRemainMoves = 0 ; this . _moveObjectAutoExecTimer = 0 ; this . updateStatusValueBox ( ) ; this . _partsAppeared = false ; this . _afterMoveMacroFlag = false ; this . _isPreparedForLookingAround = true ; this . _lookingAroundTimer = Consts . PLAYER_LOOKING_AROUND_START_FRAME ; this . _speedIndex = gameSpeedIndex ; this . _messageDelayFrameCount = 0 ; } }