#apply
#include "../_include.txt"
#include "../../define/_vector2.txt"

cev[CEV_FALCON_BOOSTER] .name("mg_ファルコンブースター") {
    def {
        //使用する変数の個数
        NUM_OF_VAR = 96
        NUM_OF_STR = 0
        NUM_OF_PIC = 190
        //レイヤー
        BASE_LAYER = 6
        //ピクチャパス
        PATH_PALLET     = "cm\p8pa"
        PATH_FRAME      = "fb\fr"
        PATH_PLAYER     = "fb\pl"
        PATH_MAP_DATA   = "fb\st_"
        PATH_MAP_CHIP   = "fb\ma"
        PATH_FONT       = "fb\fo"
        PATH_TITLE      = "fb\ti"


        //ピクチャID
        PIC_HEAD        = 1
        PIC_BACK        = 3
        PIC_SHADOW      = 5//+0_+4
        PIC_PLAYER      = 10
        PIC_MAP         = 20//+0_+130
        PIC_MAP_DATA    = 160
        PIC_STAGE       = 161//+0_+2
        PIC_GAUGE       = 165//+0_+1
        PIC_TITLE       = 169
        PIC_TIMER       = 170//+0_+7
        PIC_FADE        = 180
        PIC_FRAME       = 181

        //シーン
        SC_ST_TITLE = 0
        SC_ST_GAME
        SC_ST_CLEAR
        SC_ST_START
        SC_ST_GAMEOVER

        //トリガー
        TR_BIT_INIT_PIC    = 1 << 0
        TR_BIT_STAGE       = 1 << 1
        TR_BIT_TIMER       = 1 << 2

        //ビット
        CH_BIT_HREV        = 1 << 0
        CH_BIT_GRAVITY     = 1 << 1
        CH_BIT_BOTTOM      = 1 << 2
        CH_BIT_TOP         = 1 << 3
        CH_BIT_RIGHT       = 1 << 4
        CH_BIT_LEFT        = 1 << 5
        CH_BIT_SLOPE       = 1 << 6
        CH_BIT_LOW_CEILING = 1 << 7
        CH_BIT_GRAB        = 1 << 8

        //残像
        MAX_SHADOW = 4

        MS_TIMER = 0
        MS_CELL
        MS_X
        MS_Y
        SIZE_OF_SHADOW

        //タイマー
        MAX_TIMER = 60 * 60 * 60 - 1
        TIMER_X = 4
        TIMER_Y = 1
        TIMER_PIC = 8

        //ステージ
        MAX_STAGE = 4
        START_STAGE = 0

        STAGE_NUM_X = 4
        STAGE_NUM_Y = 10
        STAGE_NUM_PIC = 5

        //ブーストゲージ
        GAUGE_X = 4
        GAUGE_Y = 24
        GAUGE_LEN = 32
        GAUGE_PIC = 2

        //マップ
        MAP_X = SCREEN_WIDTH - 2
        MAP_Y = 2

        MAP_TILE_BLOCK = 1
        MAP_TILE_BREAK
        MAP_TILE_RIGHT_LOW
        MAP_TILE_RIGHT_HI
        MAP_TILE_LEFT_LOW
        MAP_TILE_LEFT_HI
        MAP_TILE_WARP
        MAP_TILE_GOAL
        MAP_TILE_START

        //
        OUT_RANGE = -320
        UNIT_POS = 10
        SCREEN_WIDTH  = 16 * 12
        SCREEN_HEIGHT = 16 * 9
        MAP_TILE_WIDTH  = 13
        MAP_TILE_HEIGHT = 10
        MAP_TILE_SIZE = 16
        MAP_SIZE_WIDTH  = 24
        MAP_SIZE_HEIGHT = 24
        SCROLL_OFFSET_X = SCREEN_WIDTH / 2
        SCROLL_OFFSET_Y = SCREEN_HEIGHT / 2 + 16
        FADE_TIME = 16
        REF_X = 64
        REF_Y = 48
        MID_FONT_WIDTH = 8

        //
        IN_GAME = sceneState == SC_ST_GAME
        INPUT_DECISION = (iptDec == 1 || iptY == -1) && sceneTimer > 30
    }

    //数字
    def {
        _0 = 1
        _1
        _2
        _3
        _4
        _5
        _6
        _7
        _8
        _9
        _SL
        _DO
    }


    //ピクチャの共通コマンド
    def {
        basePicCmd = bl {
            .chromakey(1)
            .mapLayer(BASE_LAYER)
            .eraseWhenTransfer
            .affectedByFlash
            .affectedByShake
        }

        playerPicCmd = bl {
            PATH_PLAYER
            .bottom
            .grid(8,4)
            basePicCmd
        }

        backPicCmd = bl {
            PATH_PALLET
            .grid(16, 1)
            basePicCmd
        }

        chipPicCmd = bl {
            PATH_MAP_CHIP
            .topLeft
            .grid(4, 2)
            basePicCmd
        }

        mapDataPicCmd = bl {
            PATH_MAP_DATA
            basePicCmd
        }

        fadePicCmd = bl {
            PATH_PALLET
            .grid(16, 1)
            basePicCmd
        }

        gaugePicCmd = bl {
            PATH_PALLET
            .grid(16, 1)
            basePicCmd
        }

        titlePicCmd = bl {
            PATH_TITLE
            .pos(REF_X, REF_Y)
            .topLeft
            .grid(2,1)
            basePicCmd
        }

        fontPicCmd = bl {
            PATH_FONT
            .grid(16,1)
            basePicCmd
        }
    }

    defv {
        varHead = TV_MINIGAME

        ipt
        pid
        cell
        state
        timer
        ground
        dir
        red
        green
        blue
        sat
        pA
        pB
        iA
        iB
        fA
        fB
        ax
        ay
        bx
        by

        triggerFlg
        sceneState
        sceneTimer
        stageCount
        fadeTimer
        savedTimer
        gameTimer
        slowMode
        slowTimer

        iptX
        iptY
        iptDec
        iptShift
        iptReset
        iptSlow

        initHead

        scrX
        scrY
        startX
        startY

        colorTimer

        plState
        plTimer
        plBit
        plCell
        plX
        plY
        plVx
        plVy
        plHeight
        plSparkDir
        plWalkTimer
        plRunTimer
        plShineTimer
        plShadowIdx
        plShadowCnt

        shadowHead
        varFoot = __id(shadowHead) + MAX_SHADOW * SIZE_OF_SHADOW
    }
    //変数の範囲を見る
    commentRangeOfVariables(varFoot, TV_MINIGAME, NUM_OF_VAR, NUM_OF_STR, NUM_OF_PIC)

    //シーンの状態を変える
    __fn _changeSceneState $state bl {
        v[__id(sceneState)..__id(sceneTimer)] = [$state, -1]
    }

    //地形用ピクチャからピクセルを取得する
    //範囲外である場合は0が入力される
    __fn _getPixelFromMap $dvPixel $x $y bl {
        v[__id($dvPixel)] = 0
        @if `between($x, 0, MAP_SIZE_WIDTH - 1) && between($y, 0, MAP_SIZE_HEIGHT - 1) bl {
            @pic.getInfo [PIC_MAP_DATA] .pixel($x, $y, 1, 1) .dst($dvPixel) .ignoreA .static
        }
    }

    //破壊可能な地形をチェックし、破壊する
    __fn _checkAndBreakTile $dvRes $cell $x $y {
        @if `$cell == MAP_TILE_BREAK && plRunTimer >= PL_RUN_TIMER bl {
            v[__id($dvRes)] = 0
            @pic.setPixel [PIC_MAP_DATA] .xywh($x, $y, 1, 1) .src($dvRes)
            v[__id($dvRes)] = TRUE
            @se.play "fc_explosion1" .opt(90, 130, 50)
        } .else bl {
            v[__id($dvRes)] = FALSE
        }        
    }

    //ピクセルからセル番号を取得する
    __fn _getMapTilePattern $dvPixel $pix bl {
        v[__id($dvPixel)] = ($pix) & 0xff
    }

    //残像を初期化する
    __fn _initShadow $ptr $block bl {
        $block
        v[$ptr..$ptr + SIZE_OF_SHADOW - 1] = [$timer, $cell, $x, $y]
    }
    //影のポインタを取得する
    __fn _getShadowPtr $dvPtr $idx bl {
        v[__id($dvPtr)] = __id(shadowHead) + ($idx) * SIZE_OF_SHADOW
    }
    //プレイヤーの状態を変える
    __fn _changePlayerState $state bl {
        v[__id(plState)..__id(plTimer)] = [$state, -1]
    }
    //目標速度と加速度を設定する
    __fn _setVelocityParam $tag $acc {
        v[__id(fA)..__id(fB)] = [$tag, $acc]
    }
    //フェードイン
    __fn _fadeIn bl {
        fadeTimer = FADE_TIME + 1
    }
    //数値を表示する
    //fA, fB, ax, ay, pid, cell
    __fn _showCounter $num $pid $dig $width $x $y bl {
        fB = 1
        @loop $dig .dst(fA) bl {
            v[__id(ax)..__id(ay)] = [($x) - fA * $width, ($y)]
            pid  = ($pid) + fA
            cell = (($num) < fB && fB != 1) ? (0) : (_0 + ($num) % (fB * 10) / fB)
            @pic.show [pid] .pos(ax, ay) .topRight .scale(100) .cell(cell) fontPicCmd  
            //次の桁
            fB *= 10
        }
    }

    //------------------------------------------------------------------------------------
    //開始処理
    bl {
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, TS_MINIGAME, NUM_OF_STR)
        msgBottom()
        @scr.tint .rgbs(50, 50, 50, 100) .time(1)
        //枠
        @pic.show[PIC_FRAME] PATH_FRAME .pos(0, 0) .topLeft basePicCmd
        //背景
        @pic.show[PIC_BACK] .pos(REF_X + SCREEN_WIDTH / 2, REF_Y + SCREEN_HEIGHT / 2) .center .scale2(100 * SCREEN_WIDTH / 8, 100 * SCREEN_HEIGHT / 8) .cell(1) backPicCmd
        @label.jump "gameLoop"
    }

    //------------------------------------------------------------------------------------
    //ゲーム処理
    @label.set "gameLoop"
    bl {
        //入力抑制
        iptDec = 2
        iptShift = 2
        iptReset = 2
        iptSlow = 2

        //ハイスコアをタイトルに表示する
        gameTimer = falconBoosterScore
        
        //タイトル
        _changeSceneState(SC_ST_TITLE)
        _fadeIn()

        //----------------------------
        //ループ
        @loop bl {
            @wait(0)
            //----------------------------
            //ポーズ
            pauseProcces(TRUE, ipt, "gameEnd")

            //----------------------------
            //スロー
            @if `slowMode bl {
                slowTimer += 1
                @if `slowTimer % 2 bl {
                    @continue
                }
            }
            @if iptSlow == 1 bl {
                slowMode = !slowMode
                slowTimer = 0

                fA = slowMode ? 50 : 100
                @se.play "fc_coin1" .opt(90, fA, 50)
            }

            //----------------------------
            //入力
            V2_getInput(iptX)
            //決定
            @key.input .dst(ipt) .decision
            iptDec = ipt ? iptDec + 1 : 0
            //Shift
            @key.input .dst(ipt) .shift
            iptShift = ipt ? iptShift + 1 : 0
            //Reset
            @key.input .dst(ipt) .number
            iptReset = (ipt == 11) ? iptReset + 1 : 0
            //Slow
            @key.input .dst(ipt) .number
            iptSlow = (ipt == 12) ? iptSlow + 1 : 0

            //----------------------------
            //シーン
            sceneTimer += 1

            pseudoSwitchState(sceneState,
            //ゲームシーン
            [ SC_ST_GAME, bl {
                //タイマー
                //スロー中は２倍の速さでカウントする
                gameTimer = min(gameTimer + (slowMode ? 2 : 1), MAX_TIMER)
                bitOn(triggerFlg, TR_BIT_TIMER)

                //クリア
                @if `plState & PL_ST_CLEAR bl {
                    _changeSceneState(SC_ST_CLEAR)
                //やりなおし
                } .elif iptReset == 1 bl {
                    _changeSceneState(SC_ST_START)
                    _fadeIn()
                    @se.play "ut_encounter" .opt(80, 80, 50)
                }
            },
            //スタート
            SC_ST_START, bl {
                @if sceneTimer == 0 bl {
                    //ステージデータ
                    @pic.show[PIC_MAP_DATA] .repl(1, stageCount) .pos(REF_X + MAP_X, REF_Y + MAP_Y) .topRight mapDataPicCmd

                    //タイマー
                    gameTimer = savedTimer

                    //スタート地点を読み込む
                    @if startX <= 0 bl {
                        @loop MAP_SIZE_HEIGHT .dst(ay) bl {
                            @loop MAP_SIZE_WIDTH .dst(ax) bl {
                                _getPixelFromMap(fA, ax, ay)
                                _getMapTilePattern(cell, fA)
                                @if cell == MAP_TILE_START bl {
                                    V2_set(startX,
                                        ax * MAP_TILE_SIZE + MAP_TILE_SIZE / 2,
                                        ay * MAP_TILE_SIZE + MAP_TILE_SIZE - PL_CORRECT
                                    )
                                    V2_asMulScalar(startX, UNIT_POS)
                                    @break(2)
                                }                             
                            }
                        }
                    }

                    //プレイヤー初期化
                    v[__id(plState)..__id(plShadowCnt)] = 0
                    V2_set(scrX, 0, 0)
                    V2_copy(plX, startX)
                    bitOn(plBit, CH_BIT_GRAVITY)
                    _changePlayerState(PL_ST_GROUND)

                    //表示
                    bitOn(triggerFlg, TR_BIT_STAGE)

                    //即開始する
                    _changeSceneState(SC_ST_GAME)
                }
            },
            //ステージクリア
            SC_ST_CLEAR, bl {
                //最後のステージをクリアすると同時にハイスコアを更新する
                @if sceneTimer == 0 bl {
                    @se.play "fc_get1" .opt(80, 100, 50)
                    @if stageCount >= MAX_STAGE - 1 bl {

                        @if `falconBoosterScore <= 0 || gameTimer < falconBoosterScore bl {
                            falconBoosterScore = gameTimer
                            @se.play "cheers" .opt(100, 100, 50)
                        }
                    }
                }

                @if `(sceneTimer == 120 && stageCount + 1 >= MAX_STAGE) ||
                     (sceneTimer == 60  && stageCount + 1 <  MAX_STAGE) bl {
                    //スタート地点を初期化する
                    V2_set(startX, 0, 0)
                    //タイマーを保存する
                    savedTimer = gameTimer
                    //次のステージへ / ゲームクリア
                    stageCount += 1
                    @if stageCount >= MAX_STAGE bl {
                        _changeSceneState(SC_ST_GAMEOVER)
                    } .else bl {
                        _changeSceneState(SC_ST_START)
                        @se.play "fc_up1" .opt (80, 100, 50)
                    }
                    //ピクチャを初期化する
                    bitOn(triggerFlg, TR_BIT_INIT_PIC)

                    _fadeIn()
                }
            },
            //ゲームオーバー
            SC_ST_GAMEOVER, bl {
                //ピクチャを設置する
                @if sceneTimer == 0 bl {
                    @pic.show[PIC_TITLE] PATH_TITLE .cell(2) titlePicCmd
                    //スコアを表示する
                    bitOn(triggerFlg, TR_BIT_TIMER)
                }

                //謎のジングル
                $A = 40
                $B = 10
                @if `sceneTimer >= $A bl {
                    @if `sceneTimer == $A || sceneTimer == $A + $B * 4 || sceneTimer == $A + $B * 12 || sceneTimer == $A + $B * 16 bl {
                        @se.play "dj_scratch1" .opt(90, 105, 50)
                    }
                    @if sceneTimer == $A + $B * 8 bl {
                        @se.play "voice_ahhun" .opt(100, 100, 50)
                    }
                    @if sceneTimer == $A + $B * 20 bl {
                        @se.play "voice_ahhun" .opt(100, 60, 50)
                    }
                }
                //タイトルに戻る
                @if `INPUT_DECISION bl {
                    _changeSceneState(SC_ST_TITLE)
                    bitOn(triggerFlg, TR_BIT_INIT_PIC)
                    _fadeIn()

                    @se.stop
                    @se.play "fc_coin1" .opt(90, 80, 50)
                }

            },
            //タイトル画面
            SC_ST_TITLE, bl {
                @if sceneTimer == 0 bl {
                    @pic.show[PIC_TITLE] PATH_TITLE .cell(1) titlePicCmd
                    //スコアを表示する
                    bitOn(triggerFlg, TR_BIT_TIMER)
                }
                //決定キーか上を押すと開始する
                @if `INPUT_DECISION bl {
                    _changeSceneState(SC_ST_START)

                    //変数初期化
                    assignVarUsingDeclared(initHead, varFoot, 0)
                    gameTimer = 0
                    savedTimer = 0
                    stageCount = START_STAGE
                    //ピクチャ初期化
                    bitOn(triggerFlg, TR_BIT_INIT_PIC)

                    _fadeIn()

                    @se.play "fc_coin1" .opt(90, 80, 50)
                }
            } ] )

            //----------------------------
            //ゲームシーン中の処理
            @if `IN_GAME bl {
                //----------------------------
                //スクロール
                V2_set(scrX,
                    plX / UNIT_POS - SCROLL_OFFSET_X,
                    plY / UNIT_POS - SCROLL_OFFSET_Y
                )
                V2_clampPointInsideRect2(scrX, 0, 0, MAP_SIZE_WIDTH * MAP_TILE_SIZE - SCREEN_WIDTH, MAP_SIZE_HEIGHT * MAP_TILE_SIZE - SCREEN_HEIGHT)

                //----------------------------
                //色
                colorTimer = (colorTimer + 1) % (4 * 2)

                //----------------------------
                //プレイヤー
                def {
                    PL_WIDTH_HALF    = 4 * UNIT_POS
                    PL_HEIGHT_STAND  = 24 * UNIT_POS
                    PL_HEIGHT_CROUCH = 14 * UNIT_POS
                    PL_GROUND_SUCK   = 8 * UNIT_POS
                    PL_GRAB_Y        = 2 * UNIT_POS
                    PL_CORRECT       = 1
                    PL_VX_TAG_WALK   = 2 * UNIT_POS
                    PL_VX_ACC_WALK   = 3
                    PL_VX_TAG_SLI    = 2 * UNIT_POS
                    PL_VX_ACC_SLI    = 8 * UNIT_POS
                    PL_VX_TAG_AIR    = 2 * UNIT_POS
                    PL_VX_ACC_AIR    = 1
                    PL_VX_TAG_WALL   = 2 * UNIT_POS
                    PL_VX_TAG_RUN    = 3 * UNIT_POS
                    PL_VX_ACC_RUN    = 8 * UNIT_POS
                    PL_VX_ACC_ACTIVE = 8 * UNIT_POS
                    PL_VX_ACC_CROUCH = 8 * UNIT_POS
                    PL_SHINE_VEL     = 8 * UNIT_POS

                    PL_MAX_VX        = 8 * UNIT_POS
                    PL_MAX_VY        = 8 * UNIT_POS
                    PL_JUMP_VY       = 4 * UNIT_POS
                    PL_JUMP_SHINE_VY = 2 * UNIT_POS
                    PL_AIR_BRAKE_VY  = 3
                    PL_GRAVITY       = 2
                    PL_MAX_VY_WALL   = 1 * UNIT_POS
                    PL_SHADOW_COUNT  = 3
                    PL_SHADOW_TIMER  = 12
                    PL_SHINE_TIMER   = 5 * UNIT_FPS
                    PL_RUN_TIMER     = 60//1.33s

                    PL_SPARK_DIR_UPLEFT = 0
                    PL_SPARK_DIR_UP
                    PL_SPARK_DIR_UPRIGHT
                    PL_SPARK_DIR_LEFT
                    PL_SPARK_DIR_NONE
                    PL_SPARK_DIR_RIGHT
                    PL_SPARK_DIR_DOWNLEFT
                    PL_SPARK_DIR_DOWN
                    PL_SPARK_DIR_DOWNRIGHT

                    PL_SHINE_TIMER1 = 30
                    PL_SHINE_TIMER2 = 20

                    //プレイヤー
                    PL_ST_NONE    = 0
                    PL_ST_GROUND  = 1 << 0
                    PL_ST_WALK    = 1 << 1
                    PL_ST_CROUCH  = 1 << 2
                    PL_ST_LANDING = 1 << 3
                    PL_ST_SLIDING = 1 << 4
                    PL_ST_FALL    = 1 << 5
                    PL_ST_JUMP    = 1 << 6
                    PL_ST_WALL    = 1 << 7
                    PL_ST_READY   = 1 << 8
                    PL_ST_SHINE   = 1 << 9
                    PL_ST_BRAKE   = 1 << 10
                    PL_ST_CLEAR   = 1 << 11
                }
                bl {
                    //タイマー
                    plTimer += 1
                    //接地フラグ
                    ground = (plBit & CH_BIT_BOTTOM) ? 1 : 0
                    //フラグ初期化
                    bitOff(plBit, CH_BIT_BOTTOM | CH_BIT_TOP | CH_BIT_RIGHT | CH_BIT_LEFT | CH_BIT_SLOPE | CH_BIT_LOW_CEILING | CH_BIT_GRAB)
                    //判定に使う頭の高さを更新する
                    plHeight = (plState & (PL_ST_CROUCH | PL_ST_SLIDING)) ? PL_HEIGHT_CROUCH : PL_HEIGHT_STAND

                    //重力
                    @if `plBit & CH_BIT_GRAVITY bl {
                        plVy += PL_GRAVITY
                    }

                    //----------------------------
                    //マップタイルとの衝突判定
                    //キャラクターの中央辺りから真下に線を伸ばし、地形に当たった部分の高さを取得する
                    V2_set(ax, plX, plY - plHeight / 2)
                    V2_asDivScalar(ax, UNIT_POS * MAP_TILE_SIZE)
                    //適当に３マス下におろす
                    @loop 3 {
                        _getPixelFromMap(fA, ax, ay)
                        _getMapTilePattern(cell, fA)
                        @if `between(cell, MAP_TILE_BLOCK, MAP_TILE_GOAL) bl {
                            //高さ
                            fB = -1
                            //ブロック / 破壊可能ブロック
                            @if `cell == MAP_TILE_BLOCK || cell == MAP_TILE_BREAK bl {
                                fB = ay * MAP_TILE_SIZE * UNIT_POS
                            //右上がり_下
                            } .elif cell == MAP_TILE_RIGHT_LOW bl {
                                fB = (plX + plVx - ax * MAP_TILE_SIZE * UNIT_POS) / -2 + MAP_TILE_SIZE * UNIT_POS + ay * MAP_TILE_SIZE * UNIT_POS
                            //右上がり_上
                            } .elif cell == MAP_TILE_RIGHT_HI bl {
                                fB = (plX + plVx - ax * MAP_TILE_SIZE * UNIT_POS) / -2 + MAP_TILE_SIZE * UNIT_POS / 2 + ay * MAP_TILE_SIZE * UNIT_POS
                            //左上がり_上
                            } .elif cell == MAP_TILE_LEFT_LOW bl {
                                fB = (plX + plVx - ax * MAP_TILE_SIZE * UNIT_POS) / 2 + ay * MAP_TILE_SIZE * UNIT_POS
                            //左上がり_下
                            } .elif cell == MAP_TILE_LEFT_HI bl {
                                fB = (plX + plVx - ax * MAP_TILE_SIZE * UNIT_POS) / 2 + MAP_TILE_SIZE * UNIT_POS / 2 + ay * MAP_TILE_SIZE * UNIT_POS
                            }
                            //高さ修正
                            @if fB >= 0 bl {
                                //地上にいる場合、多めに吸い付く
                                @if `(ground && fB - plY <= PL_GROUND_SUCK) || (plY + plVy >= fB) bl {
                                    _checkAndBreakTile(fA, cell, ax, ay)
                                    @if `!fA bl {
                                        plY = fB - PL_CORRECT
                                        plVy = 0
                                        bitOn(plBit, CH_BIT_BOTTOM)
                                        //坂
                                        @if `between(cell, MAP_TILE_RIGHT_LOW, MAP_TILE_LEFT_HI) bl {
                                            bitOn(plBit, CH_BIT_SLOPE)
                                        }
                                    }
                                }
                                @break
                            }
                        }
                        //判定位置を１マス下げる
                        ay += 1
                    }

                    //上下にブロックがあるか判定する
                    //横移動は無視し、垂直移動のみ考慮する
                    @loop 2 .dst(iA) bl {
                        //上下
                        ipt = plVy > 0 ? 0 : 1
                        //判定高さ
                        by = [0, plHeight][ipt]
                        //判定マス
                        V2_set(ax,
                            plX + [-1, 1][iA] * PL_WIDTH_HALF,//少し幅を狭める
                            plY + plVy - by
                        )
                        V2_asDivScalar(ax, UNIT_POS * MAP_TILE_SIZE)
                        //マス取得
                        _getPixelFromMap(fA, ax, ay)
                        _getMapTilePattern(cell, fA)
                        //高さ
                        fB = -1
                        //ブロック / 破壊可能ブロック
                        @if `cell == MAP_TILE_BLOCK || cell == MAP_TILE_BREAK bl {
                            fB = (ay + ipt) * UNIT_POS * MAP_TILE_SIZE
                        }
                        //高さ修正
                        @if fB >= 0 bl {
                            _checkAndBreakTile(fA, cell, ax, ay)
                            @if `!fA bl {

                                plVy = 0
                                //頭上
                                @if `ipt bl {
                                    plY = fB + PL_CORRECT + plHeight
                                    bitOn(plBit, CH_BIT_TOP)
                                //足元
                                } .else bl {
                                    plY = fB - PL_CORRECT
                                    bitOn(plBit, CH_BIT_BOTTOM)
                                }
                            }
                        }
                    }

                    //縦に移動
                    plY += plVy

                    //左右にブロックがあるか判定する
                    //縦移動を無視し、横移動のみ考慮する
                    @loop 2 .dst(iA) bl {
                        //左右
                        ipt = plVx > 0 ? 0 : 1
                        //判定高さ
                        //乗り上げやすいように少しずらす
                        by = [4 * UNIT_POS, plHeight - 4 * UNIT_POS][iA]
                        //判定マス
                        V2_set(ax,
                            plX + plVx + [1, -1][ipt] * PL_WIDTH_HALF,
                            plY - by
                        )
                        V2_asDivScalar(ax, UNIT_POS * MAP_TILE_SIZE)
                        //マス取得
                        _getPixelFromMap(fA, ax, ay)
                        _getMapTilePattern(cell, fA)
                        //衝突位置
                        fB = -1
                        //ブロック / 破壊可能ブロック
                        @if `cell == MAP_TILE_BLOCK || cell == MAP_TILE_BREAK bl {
                            fB = (ax + ipt) * MAP_TILE_SIZE * UNIT_POS 
                        }
                        //高さ修正
                        @if fB >= 0 bl {
                            _checkAndBreakTile(fA, cell, ax, ay)
                            @if `!fA bl {
                                plVx = 0
                                @if `ipt bl {
                                    plX = fB + PL_CORRECT + PL_WIDTH_HALF
                                    bitOn(plBit, CH_BIT_LEFT)
                                } .else bl {
                                    plX = fB - PL_CORRECT - PL_WIDTH_HALF
                                    bitOn(plBit, CH_BIT_RIGHT)
                                }
                            }
                        }
                    }

                    //横に移動
                    plX += plVx

                    //頭上にブロックがあるか判定する
                    //しゃがみ状態から戻る際に使用する
                    @loop 2 .dst(iA) bl {
                        //判定マス
                        V2_set(ax,
                            plX + [-1, 1][iA] * PL_WIDTH_HALF,
                            plY - PL_HEIGHT_STAND
                        )
                        V2_asDivScalar(ax, UNIT_POS * MAP_TILE_SIZE)
                        //マス取得
                        _getPixelFromMap(fA, ax, ay)
                        _getMapTilePattern(cell, fA)
                        //ブロック / 破壊可能ブロック
                        @if `cell == MAP_TILE_BLOCK || cell == MAP_TILE_BREAK bl {
                            bitOn(plBit, CH_BIT_LOW_CEILING)
                            @break
                        }
                    }

                    //掴み判定
                    @if `plBit & (CH_BIT_LEFT | CH_BIT_RIGHT) bl {
                        //判定マス
                        V2_set(ax,
                            plX + ((plBit & CH_BIT_HREV) ? -1 : 1) * (PL_WIDTH_HALF + PL_CORRECT + 1),
                            plY - plHeight - PL_GRAB_Y + PL_CORRECT
                        )
                        V2_asDivScalar(ax, UNIT_POS * MAP_TILE_SIZE)
                        //マス取得
                        _getPixelFromMap(fA, ax, ay)
                        _getMapTilePattern(cell, fA)
                        //ブロック / 破壊可能ブロック
                        @if `cell == MAP_TILE_BLOCK || cell == MAP_TILE_BREAK bl {
                        } .else bl {
                            bitOn(plBit, CH_BIT_GRAB)
                        }
                    }

                    //キャラクターの中央を調べる
                    //判定マス
                    V2_set(ax,
                        plX,
                        plY - plHeight / 2
                    )
                    V2_asDivScalar(ax, UNIT_POS * MAP_TILE_SIZE)
                    //マス取得
                    _getPixelFromMap(fA, ax, ay)
                    _getMapTilePattern(cell, fA)
                    //ゴール判定
                    @if cell == MAP_TILE_GOAL bl {
                        _changePlayerState(PL_ST_CLEAR)
                    }

                    //念のため、ステージの端とも判定する
                    $MAP_WIDTH_PX  = MAP_SIZE_WIDTH * MAP_TILE_SIZE
                    $MAP_HEIGHT_PX = MAP_SIZE_HEIGHT * MAP_TILE_SIZE
                    @if `plX - PL_WIDTH_HALF + plVx < 0 bl {
                        plX = PL_WIDTH_HALF
                        plVx = 0
                        bitOn(plBit, CH_BIT_LEFT)
                    }

                    @if `plX + PL_WIDTH_HALF + plVx > $MAP_WIDTH_PX * UNIT_POS bl {
                        plX = $MAP_WIDTH_PX * UNIT_POS - PL_WIDTH_HALF
                        plVx = 0
                        bitOn(plBit, CH_BIT_RIGHT)
                    }

                    @if `plY + plVy < 0 bl {
                        plY = 0
                        plVy = 0
                        bitOn(plBit, CH_BIT_TOP)
                    }
                    
                    @if `plY + plVy - plHeight > $MAP_HEIGHT_PX * UNIT_POS bl {
                        plY = $MAP_HEIGHT_PX * UNIT_POS + plHeight
                        plVy = 0
                        bitOn(plBit, CH_BIT_BOTTOM)
                    }

                    //----------------------------
                    //状態
                    state = plState
                    //向き
                    dir = (plBit & CH_BIT_HREV) ? (-1) : (1)
                    //目標値
                    fA = 0
                    //加速値
                    fB = 0

                    //頭上が狭くない
                    $ABLE_STAND = (!(plBit & CH_BIT_LOW_CEILING))

                    //共通処理
                    //振り向き
                    @if `state & (PL_ST_GROUND | PL_ST_WALK | PL_ST_LANDING | PL_ST_CROUCH | PL_ST_FALL | PL_ST_JUMP) bl {
                        //ブースト走行状態のときは空中で振り向けない
                        @if `iptX != dir && iptX != 0 &&
                             !((state & (PL_ST_FALL | PL_ST_JUMP)) && plRunTimer >= PL_RUN_TIMER) bl {
                            //振り向くと助走タイマーを初期化
                            dir = iptX > 0 ? 1 : -1
                            plRunTimer = 0
                        }
                    }

                    //壁擦り
                    $WALL_CANCEL = (iptY > 0)
                    $HIT_WALL = (((plBit & CH_BIT_RIGHT) && dir > 0) || ((plBit & CH_BIT_LEFT) && dir < 0))
                    $WALL_STATE = (state & PL_ST_WALL)
                    @if `state & (PL_ST_FALL | PL_ST_JUMP | PL_ST_WALL) bl {
                        //擦り開始
                        @if `plVy >= 0 && $HIT_WALL && !$WALL_STATE bl {
                            //下を押しっぱなしでそのまま落下するが、ブーストはキャンセルされる
                            @if `$WALL_CANCEL bl {
                                //ブースト走行中だとキャンセルする
                                @if plRunTimer > 0 bl {
                                    plRunTimer = 0
                                }
                            } .else bl {
                                state = PL_ST_WALL
                                _setVelocityParam(0, 0)
                                V2_set(plVx, 0, 0)
                            }
                        //擦りキャンセル
                        } .elif `($WALL_CANCEL || !$HIT_WALL) && $WALL_STATE bl {
                            state = PL_ST_FALL
                            //ブースト走行中だとキャンセルする
                            @if plRunTimer > 0 bl {
                                plRunTimer = 0
                            }
                        }
                    }

                    //着地
                    @if `plBit & CH_BIT_BOTTOM bl {
                        @if `state & (PL_ST_FALL | PL_ST_JUMP | PL_ST_WALL) bl {
                            state = PL_ST_LANDING
                            @se.play "fc_ground1" .opt 100, 100, 50
                        }
                    //落下
                    } .else bl {
                        @if `(state & (PL_ST_GROUND | PL_ST_WALK | PL_ST_LANDING | PL_ST_CROUCH)) && $ABLE_STAND bl {
                            state = PL_ST_FALL
                        }
                    }

                    //空中動作
                    $FLOW_INPUT = (iptDec > 0)
                    @if `state & (PL_ST_FALL | PL_ST_JUMP) bl {
                        //横移動
                        _setVelocityParam(iptX * PL_VX_TAG_AIR, PL_VX_ACC_AIR)
                        //決定を離すと減速する
                        @if `!$FLOW_INPUT && plVy < 0 bl {
                            plVy += PL_AIR_BRAKE_VY
                        }
                    }

                    //シャインスパーク
                    //地上にいる時は横入力なしで決定
                    //空中にいる時は決定のみ
                    $SHINE_INPUT = (iptDec == 1 && iptX == 0)
                    @if `(state & (PL_ST_GROUND | PL_ST_WALK | PL_ST_LANDING | PL_ST_CROUCH | PL_ST_FALL | PL_ST_JUMP)) && $ABLE_STAND bl {
                        @if plShineTimer > 0 bl {
                            @if `$SHINE_INPUT bl {
                                state = PL_ST_READY
                                _setVelocityParam(0, 0)
                                V2_set(plVx, 0, 0)
                                bitOff(plBit, CH_BIT_GRAVITY | CH_BIT_BOTTOM)

                                plRunTimer = PL_RUN_TIMER
                                plShineTimer = PL_SHINE_TIMER
                            }
                        }
                    }

                    //屈む
                    $CROUCH_INPUT = (iptY > 0 && iptShift <= 0)
                    $CROUCH_STATE = (state & PL_ST_CROUCH)
                    @if `state & (PL_ST_GROUND | PL_ST_WALK | PL_ST_LANDING | PL_ST_SLIDING | PL_ST_CROUCH) bl {
                        //屈む
                        @if `$CROUCH_INPUT && !$CROUCH_STATE bl {
                            state = PL_ST_CROUCH

                            //ブースト走行状態の時に屈むと光る
                            @if plRunTimer >= PL_RUN_TIMER bl {
                                plRunTimer = 0
                                plShineTimer = PL_SHINE_TIMER
                            }
                        //屈み解除
                        } .elif `!$CROUCH_INPUT && $CROUCH_STATE && $ABLE_STAND bl {
                            state = PL_ST_GROUND
                        }
                    }

                    //歩き
                    $WALK_INPUT = (iptX != 0)
                    $WALK_STATE = (state & PL_ST_WALK)
                    $WALK_SPEED = (plVx != 0)
                    $WALK_HIT_WALL = (((plBit & CH_BIT_LEFT) && dir < 0) || ((plBit & CH_BIT_RIGHT) && dir > 0))
                    @if `state & (PL_ST_GROUND | PL_ST_WALK | PL_ST_LANDING) bl {
                        //壁に衝突していると歩かない
                        @if `$WALK_HIT_WALL && $WALK_STATE bl {
                            state = PL_ST_GROUND
                        //歩き開始
                        } .elif `$WALK_SPEED && !$WALK_STATE bl {
                            state = PL_ST_WALK
                            //アニメーション用タイマーを初期化する
                            plWalkTimer = 0
                        //歩き解除
                        } .elif `!$WALK_SPEED && !$WALK_INPUT && $WALK_STATE bl {
                            state = PL_ST_GROUND
                        }
                    }

                    //スライディング
                    //ブースト走行中は斜め下入力で出せる  
                    $JUMP_INPUT = (iptDec == 1)
                    $SLIDING_INPUT = (iptShift == 1)
                    $SLIDING_STATE = (state & PL_ST_SLIDING)
                    @if `state & (PL_ST_GROUND | PL_ST_WALK | PL_ST_LANDING | PL_ST_SLIDING | PL_ST_CROUCH) bl {
                        //スライディング開始
                        @if `$SLIDING_INPUT && !$SLIDING_STATE bl {
                            state = PL_ST_SLIDING
                            @se.play "fc_jump1" .opt(60, 150, 50)
                        //スライディングジャンプ
                        } .elif `$JUMP_INPUT && $SLIDING_STATE && $ABLE_STAND bl {
                            state = PL_ST_JUMP
                            plVy = PL_JUMP_VY * -1
                            bitOff(plBit, CH_BIT_BOTTOM)
                            @se.play "fc_jump1" .opt(100, 100, 50)
                        }
                    }

                    //ジャンプ
                    @if `(state & (PL_ST_GROUND | PL_ST_WALK | PL_ST_LANDING | PL_ST_CROUCH)) && $ABLE_STAND bl {
                        @if `$JUMP_INPUT bl { 
                            state = PL_ST_JUMP
                            plVy = PL_JUMP_VY * -1
                            bitOff(plBit, CH_BIT_BOTTOM)
                            @se.play "fc_jump1" .opt(100, 100, 50)
                        }
                    }
                    //壁ジャンプ
                    @if `state & (PL_ST_WALL) bl {
                        @if `$JUMP_INPUT bl {
                            state = PL_ST_JUMP

                            //崖際で壁方向に入力していると反転しない
                            ipt = iptX > 0 ? 1 : -1
                            @if `(plBit & CH_BIT_GRAB) && dir == iptX bl {
                            } .else bl {
                                //反転して跳ぶ
                                dir *= -1
                                @if plRunTimer >= PL_RUN_TIMER bl {
                                    plVx = PL_VX_TAG_RUN * dir
                                } .else bl {
                                    plVx = PL_VX_TAG_WALL * dir
                                }
                            }
                            plVy = PL_JUMP_VY * -1
                            bitOff(plBit, CH_BIT_BOTTOM)
                            @se.play "fc_jump1" .opt(100, 100, 50)
                        }
                    }

                    //状態ごとの処理を行う前に状態を更新する
                    @if state != plState bl {
                        _changePlayerState(state)
                    }

                    //状態ごとの処理
                    pseudoSwitchState(state,
                    [   PL_ST_GROUND, bl {
                            _setVelocityParam(iptX * PL_VX_TAG_WALK, PL_VX_ACC_WALK)
                        },
                        PL_ST_WALK, bl {
                            _setVelocityParam(iptX * PL_VX_TAG_WALK, PL_VX_ACC_WALK)

                            @if plRunTimer < PL_RUN_TIMER bl {
                                plRunTimer += 1
                            } .else bl {
                                @if iptX != dir bl {
                                    plRunTimer = 0
                                }
                            }
                        },
                        PL_ST_CROUCH, bl {
                            _setVelocityParam(0, PL_VX_ACC_CROUCH)
                        },
                        PL_ST_LANDING, bl {
                            //アニメーションが終わると立ち状態へ移行
                            @if `plTimer >= 4 * 2 bl {
                                state = PL_ST_GROUND
                            }
                        },
                        PL_ST_SLIDING, bl {
                            //壁にぶつからず、Shiftを押し続ける限り続く
                            $WALK_HIT_WALL = (((plBit & CH_BIT_LEFT) && dir < 0) || ((plBit & CH_BIT_RIGHT) && dir > 0))
                            @if `iptShift > 0 && !$WALK_HIT_WALL bl {
                                _setVelocityParam(dir * PL_VX_TAG_SLI, PL_VX_ACC_SLI)
                            //スライディング発動直後は以下の判定を行わない
                            } .elif plTimer > 0 bl {
                                @if `plBit & CH_BIT_LOW_CEILING bl {
                                    state = PL_ST_CROUCH
                                } .elif `plBit & CH_BIT_BOTTOM bl {
                                    state = PL_ST_WALK
                                } .else bl {
                                    state = PL_ST_FALL
                                }
                            }
                        },
                        PL_ST_FALL, bl {
                        },
                        PL_ST_JUMP, bl {
                            //アニメーションが終わると落下動作に移行
                            @if plTimer >= 4 * 6 bl {
                                state = PL_ST_FALL
                            }
                        },
                        PL_ST_WALL, bl {
                            //少し押し付ける
                            plVx = dir * (PL_CORRECT + 1)
                            //落下速度を制限する
                            plVy = min(plVy, PL_MAX_VY_WALL)
                            //壁に触れていないと落下する
                            @if `(dir < 0 && plBit & CH_BIT_RIGHT) ||
                                 (dir > 0 && plBit & CH_BIT_LEFT) bl {
                                state = PL_ST_FALL
                            }
                        },
                        PL_ST_READY, bl {
                            //入力が無いと真上に飛ぶ
                            @if plTimer == 0 bl {
                                plSparkDir = PL_SPARK_DIR_UP
                            }
                            //一定時間後、最後に入力した方向に飛ぶ
                            ipt = (iptX + 1) + (iptY + 1) * 3
                            @if ipt != PL_SPARK_DIR_NONE bl {
                                plSparkDir = ipt
                                //接触フラグを初期化
                                bitOff(plBit, CH_BIT_LEFT | CH_BIT_RIGHT | CH_BIT_TOP | CH_BIT_BOTTOM)
                            }
                            @if plTimer >= PL_SHINE_TIMER1 bl {
                                state = PL_ST_SHINE
                            
                                //向きを変える
                                @if `plSparkDir % 3 == 0 bl {
                                    dir = -1
                                } .elif `plSparkDir % 3 == 2 bl {
                                    dir = 1
                                }

                                @se.play "fc_break3" .opt(80, 100, 50)
                            }
                        },
                        PL_ST_SHINE, bl {
                            ipt = [-135, -90, -45, 180, 0, 0, 135, 90, 45][plSparkDir]
                            V2_getCosSin(plVx, ipt, 1, PL_SHINE_VEL)
                            _setVelocityParam(0, 0)

                            //坂に着地すると走行状態に戻る
                            //垂直移動の場合は除く
                            @if `(plBit & CH_BIT_BOTTOM) && (plBit & CH_BIT_SLOPE) && (plSparkDir % 3 != 1) bl {
                                state = PL_ST_WALK
                                bitOn(plBit, CH_BIT_GRAVITY)

                                plRunTimer = PL_RUN_TIMER
                                plShineTimer = 0
                            //衝突判定
                            } .else bl {
                                ipt = 0
                                //上下
                                @if `plSparkDir % 3 == 1 bl {
                                    ipt = plBit & (CH_BIT_TOP | CH_BIT_BOTTOM)
                                //左右
                                } .elif `plSparkDir / 3 == 1 bl {
                                    ipt = plBit & (CH_BIT_LEFT | CH_BIT_RIGHT)
                                //斜め
                                } .else bl {
                                    ipt = plBit & (CH_BIT_LEFT | CH_BIT_RIGHT | CH_BIT_TOP | CH_BIT_BOTTOM)
                                }
                                //衝突
                                @if `ipt bl {
                                    state = PL_ST_BRAKE
                                    V2_set(plVx, 0, 0)
                                    @se.play "fc_explosion1" .opt(80, 80, 50)
                                }
                            }
                        },
                        PL_ST_BRAKE, bl {
                            @if plTimer > PL_SHINE_TIMER2 bl {
                                bitOn(plBit, CH_BIT_GRAVITY)

                                plShineTimer = 0
                                plRunTimer = 0

                                //下にぶつかると着地動作になる
                                @if `plSparkDir > 5 bl {
                                    state = PL_ST_LANDING
                                } .else bl {
                                    state = PL_ST_FALL
                                }
                            }
                        }
                    ] )

                    //ブースト走行中は目標速度と加速度を上書きする
                    @if `state & (PL_ST_WALK | PL_ST_SLIDING | PL_ST_FALL | PL_ST_JUMP) bl {
                        @if plRunTimer >= PL_RUN_TIMER bl {
                            _setVelocityParam(dir * PL_VX_TAG_RUN, PL_VX_ACC_RUN)
                        }
                    }

                    //シャイン維持タイマー
                    @if `plShineTimer > 0 && !(plState & (PL_ST_READY | PL_ST_SHINE | PL_ST_BRAKE)) bl {
                        plShineTimer -= 1
                    }

                    //ブースト走行中は音が鳴る
                    @if `plState & (PL_ST_READY | PL_ST_SHINE | PL_ST_BRAKE) bl {
                    } .elif plRunTimer >= PL_RUN_TIMER bl {
                        @if `!(sceneTimer % 8) bl {
                            @se.play "fc_power2" .opt(80, 150, 50)
                        }
                    } .elif `plShineTimer > 0 bl {
                        //シャイン維持中は音が鳴る
                        @if `!(sceneTimer % 12) bl {
                            @se.play "fc_power2" .opt(80, 100, 50)
                        }
                    }

                    //ブースト走行状態を解除する
                    @if plRunTimer >= PL_RUN_TIMER bl {
                        @if `!(state & (PL_ST_WALK | PL_ST_SLIDING | PL_ST_JUMP | PL_ST_FALL | PL_ST_WALL | PL_ST_READY | PL_ST_SHINE | PL_ST_BRAKE)) bl {
                            plRunTimer = 0
                        }
                    //タイマーを初期化する
                    } .else bl {
                        @if `!(state & PL_ST_WALK) bl {
                            plRunTimer = 0
                        }
                    }

                    //状態を更新する
                    @if state != plState bl {
                        _changePlayerState(state)
                    }

                    //向きを変える
                    @if `(plBit & CH_BIT_HREV) && dir > 0 bl {
                        bitOff(plBit, CH_BIT_HREV)
                    } .elif `!(plBit & CH_BIT_HREV) && dir < 0 bl {
                        bitOn(plBit, CH_BIT_HREV)
                    }

                    //速度更新
                    @if `plVx - fB > fA bl {
                        plVx -= fB
                    } .elif `plVx + fB < fA bl {
                        plVx += fB
                    } .else bl {
                        plVx = fA
                    }

                    //アニメーション
                    pseudoSwitchState(plState,
                    [   PL_ST_GROUND, bl {
                            easyAnimation(plCell, TRUE, 1, 2, plTimer, 24)
                        },
                        PL_ST_WALK, bl {
                            //ブースト走行中は速くなる
                            @if plRunTimer >= PL_RUN_TIMER bl {
                                plWalkTimer += 2
                                easyAnimation(plCell, TRUE, 9, 16, plWalkTimer, 4)
                            } .else bl {
                                plWalkTimer += 1
                                easyAnimation(plCell, TRUE, 9, 16, plWalkTimer, 4)
                            }
                        },
                        PL_ST_CROUCH, bl {
                            easyAnimation(plCell, FALSE, 3, 4, plTimer, 4)
                        },
                        PL_ST_LANDING, bl {
                            easyAnimation(plCell, FALSE, 4, 3, plTimer, 4)
                        },
                        PL_ST_SLIDING, bl {
                            plCell = 5
                        },
                        PL_ST_FALL, bl {
                            easyAnimation(plCell, FALSE, 23, 24, plTimer, 4)
                        },
                        PL_ST_JUMP, bl {
                            easyAnimation(plCell, FALSE, 17, 22, plTimer, 4)
                        },
                        PL_ST_WALL, bl {
                            plCell = 25
                        },
                        PL_ST_READY, bl {
                            easyAnimation(plCell, FALSE, 26, 28, plTimer, 4)
                        },
                        PL_ST_SHINE, bl {
                            @if plSparkDir == PL_SPARK_DIR_UP bl {
                                plCell = 31
                            } .elif plSparkDir == PL_SPARK_DIR_DOWN bl {
                                plCell = 32
                            } .elif `plSparkDir == PL_SPARK_DIR_DOWNLEFT || plSparkDir == PL_SPARK_DIR_DOWNRIGHT bl {
                                plCell = 30
                            } .else bl {
                                plCell = 29
                            }
                        },
                        PL_ST_BRAKE, bl {
                            //変更しない
                        },
                        PL_ST_CLEAR, bl {
                            //変更しない
                        }
                    ] )

                    //移動量拘束
                    V2_clampPointInsideRect2(plVx, -PL_MAX_VX, -PL_MAX_VY, PL_MAX_VX, PL_MAX_VY)

                    //ピクチャ更新
                    //画面座標
                    V2_set(ax,
                        REF_X + (plX + UNIT_POS / 2) / UNIT_POS - scrX,
                        REF_Y + (plY + UNIT_POS / 2) / UNIT_POS - scrY
                    )
                    //透明度
                    //画面から出ると透明になる
                    fB = 0
                    @if `!between(ax, REF_X, REF_X + SCREEN_WIDTH) ||
                         !between(ay, REF_Y, REF_Y + SCREEN_HEIGHT) bl {
                        fB = 100
                    }
                    //色
                    @if `plRunTimer >= PL_RUN_TIMER || (plState & (PL_ST_READY | PL_ST_SHINE | PL_ST_BRAKE)) bl {
                        ipt   = colorTimer / 2
                        red   = [200, 150, 100, 150][ipt] - 50
                        green = [100, 150, 200, 150][ipt] - 50
                        blue  = [150, 200, 150, 100][ipt] - 50
                        sat   = 100
                    } .elif plShineTimer > 0 bl {
                        ipt   = colorTimer / 2
                        red   = [200, 150, 100, 150][ipt] - 50
                        green = [100, 100, 120, 100][ipt] - 50
                        blue  = [150, 200, 150, 100][ipt] - 50
                        sat   = 100
                    } .else bl {
                        v[__id(red)..__id(sat)] = 100
                    }
                    //左右反転
                    @if `plBit & CH_BIT_HREV bl {
                        @pic.show[PIC_PLAYER] .pos(ax, ay) .cell(plCell) .trans(fB) .rgbs(red, green, blue, sat) .hrev playerPicCmd
                    } .else bl {
                        @pic.show[PIC_PLAYER] .pos(ax, ay) .cell(plCell) .trans(fB) .rgbs(red, green, blue, sat) playerPicCmd
                    }
                }

                //----------------------------
                // 残像

                //ブーストが維持されている間は定期的に追加する
                @if `plRunTimer >= PL_RUN_TIMER || plShineTimer > 0 bl {
                    plShadowCnt -= 1
                    @if plShadowCnt <= 0 bl {
                        plShadowCnt = PL_SHADOW_COUNT
                        plShadowIdx = (plShadowIdx + 1) % MAX_SHADOW
                        cell = plCell * ((plBit & CH_BIT_HREV) ? -1 : 1)
                        _getShadowPtr(pA, plShadowIdx)
                        _initShadow(pA, bl {
                            $timer = PL_SHADOW_TIMER
                            $cell = cell
                            $x = plX
                            $y = plY
                        } )
                    }
                }

                //残像の色
                ipt = colorTimer / 2
                red   = [200, 150, 100, 150][ipt] - 50
                green = [100, 100, 120, 100][ipt] - 50
                blue  = [150, 200, 150, 100][ipt] - 50
                sat   = 0

                @loop MAX_SHADOW .dst(iA) bl {
                    _getShadowPtr(pA, iA)
                    fA = v[pA + MS_CELL]
                    @if fA == 0 bl {
                        @continue
                    }
                    //タイマー
                    v[pA + MS_TIMER] -= 1
                    //時間が来ると消去する
                    @if `v[pA + MS_TIMER] <= 0 bl {
                        v[pA + MS_CELL] = 0
                    }
                    //画面座標
                    V2_set(ax,
                        REF_X + (v[pA + MS_X] + UNIT_POS / 2) / UNIT_POS - scrX,
                        REF_Y + (v[pA + MS_Y] + UNIT_POS / 2) / UNIT_POS - scrY
                    )
                    //セル番号(負数で左右反転)
                    cell = abs(fA)
                    //ピクチャ番号
                    pid = PIC_SHADOW + iA
                    //透明度
                    fB = lerp(100, -100, v[pA + MS_TIMER], PL_SHADOW_TIMER)
                    //画面から出ると透明になる
                    @if `!between(ax, REF_X, REF_X + SCREEN_WIDTH) ||
                         !between(ay, REF_Y, REF_Y + SCREEN_HEIGHT) bl {
                        fB = 100
                    }
                    //左右反転
                    @if `fA < 0 bl {
                        @pic.show[pid] .pos(ax, ay) .cell(cell) .trans(fB) .rgbs(red, green, blue, sat) .hrev .add playerPicCmd
                    } .else bl {
                        @pic.show[pid] .pos(ax, ay) .cell(cell) .trans(fB) .rgbs(red, green, blue, sat) .add playerPicCmd
                    }
                }
                //----------------------------
                //マップ
                //a:マップ座標 b:スクリーン座標
                @loop MAP_TILE_HEIGHT .dst(iB) bl {
                    ay = iB + scrY / MAP_TILE_SIZE
                    by = iB * MAP_TILE_SIZE - scrY % MAP_TILE_SIZE + REF_Y
                    @loop MAP_TILE_WIDTH .dst(iA) bl {
                        ax = iA + scrX / MAP_TILE_SIZE
                        bx = iA * MAP_TILE_SIZE - scrX % MAP_TILE_SIZE + REF_X
                        pid = PIC_MAP + iB * MAP_TILE_WIDTH + iA

                        _getPixelFromMap(fA, ax, ay)
                        _getMapTilePattern(cell, fA)

                        @pic.show[pid] .pos(bx, by) .cell(cell) chipPicCmd
                    }
                }
                //----------------------------
                //ゲージ

                //シャイン維持
                ipt = lerp(0, GAUGE_LEN, plShineTimer, PL_SHINE_TIMER)
                V2_set(ax,
                    REF_X + GAUGE_X + ipt / 2,
                    REF_Y + GAUGE_Y + 0
                )
                V2_set(bx,
                    ipt * 100 / 8,
                    25
                )
                @pic.show[PIC_GAUGE + 0] .pos(ax, ay) .scale2(bx, by) .cell(15) gaugePicCmd

                //ブースト
                ipt = lerp(0, GAUGE_LEN, plRunTimer, PL_RUN_TIMER)
                V2_set(ax,
                    REF_X + GAUGE_X + ipt / 2,
                    REF_Y + GAUGE_Y + 4
                )
                V2_set(bx,
                    ipt * 100 / 8,
                    25
                )
                @pic.show[PIC_GAUGE + 1] .pos(ax, ay) .scale2(bx, by) .cell(13) gaugePicCmd
            }

            //----------------------------
            // フェードイン
            @if fadeTimer > 0 bl {
                fadeTimer -= 1
                @if fadeTimer <= 0 bl {
                    hidePicture(PIC_FADE)
                } .else bl {
                    fA = lerp(100, 0, fadeTimer - FADE_TIME / 2, FADE_TIME / 2)
                    fA = clamp(fA, 0, 98)
                    fB = lerp(100, 0, fadeTimer, FADE_TIME / 2)
                    fB = clamp(fB, 0, 100)
                    V2_set(ax,
                        REF_X + SCREEN_WIDTH  / 2,
                        REF_Y + SCREEN_HEIGHT / 2
                    )
                    V2_set(bx,
                        lerp(100 * SCREEN_WIDTH  / 8, 0, fB, 100),
                        lerp(100 * SCREEN_HEIGHT / 8, 0, fA, 100)
                    )
                    @pic.show[PIC_FADE] .pos(ax, ay) .center .scale2(bx, by) .cell(7) fadePicCmd
                }
            }

            //----------------------------
            //タイマーは毎F更新される
            @if `triggerFlg & TR_BIT_TIMER bl {
                bitOff(triggerFlg, TR_BIT_TIMER)

                ax = (gameTimer % UNIT_FPS) * 100 / UNIT_FPS
                ay = (gameTimer / UNIT_FPS) % 60
                bx = (gameTimer / (UNIT_FPS * 60)) % 60

                cell = bx / 10 + 1
                @pic.show[PIC_TIMER + 0] .pos(REF_X + TIMER_X + 8 * 0, REF_Y + TIMER_Y) .topLeft .cell(cell) fontPicCmd
                cell = bx % 10 + 1
                @pic.show[PIC_TIMER + 1] .pos(REF_X + TIMER_X + 8 * 1, REF_Y + TIMER_Y) .topLeft .cell(cell) fontPicCmd

                @pic.show[PIC_TIMER + 2] .pos(REF_X + TIMER_X + 8 * 2, REF_Y + TIMER_Y) .topLeft .cell(_DO)  fontPicCmd

                cell = ay / 10 + 1
                @pic.show[PIC_TIMER + 3] .pos(REF_X + TIMER_X + 8 * 3, REF_Y + TIMER_Y) .topLeft .cell(cell) fontPicCmd
                cell = ay % 10 + 1
                @pic.show[PIC_TIMER + 4] .pos(REF_X + TIMER_X + 8 * 4, REF_Y + TIMER_Y) .topLeft .cell(cell) fontPicCmd

                @pic.show[PIC_TIMER + 5] .pos(REF_X + TIMER_X + 8 * 5, REF_Y + TIMER_Y) .topLeft .cell(_DO)  fontPicCmd

                cell = ax / 10 + 1
                @pic.show[PIC_TIMER + 6] .pos(REF_X + TIMER_X + 8 * 6, REF_Y + TIMER_Y) .topLeft .cell(cell) fontPicCmd
                cell = ax % 10 + 1
                @pic.show[PIC_TIMER + 7] .pos(REF_X + TIMER_X + 8 * 7, REF_Y + TIMER_Y) .topLeft .cell(cell) fontPicCmd
            }

            triggerSwitchState(triggerFlg,
            [TR_BIT_INIT_PIC, bl {
                //タイトル
                hidePicture(PIC_TITLE)
                //ステージ番号
                @loop STAGE_NUM_PIC .dst(pid) bl {
                    pid += PIC_STAGE
                    hidePicture(pid)
                }
                //タイマー
                @loop TIMER_PIC .dst(pid) bl {
                    pid += PIC_TIMER
                    hidePicture(pid)
                }
                //ゲージ
                @loop GAUGE_PIC .dst(pid) bl {
                    pid += PIC_GAUGE
                    hidePicture(pid)
                }
                //残像
                @loop MAX_SHADOW .dst(pid) bl {
                    pid += PIC_SHADOW
                    hidePicture(pid)
                }
                //プレイヤー
                hidePicture(PIC_PLAYER)
                //マップチップ
                fA = MAP_TILE_WIDTH * MAP_TILE_HEIGHT
                @loop fA .dst(pid) {
                    pid += PIC_MAP
                    hidePicture(pid)
                }
                //マップデータ
                hidePicture(PIC_MAP_DATA)
            },
            TR_BIT_STAGE, bl {
                cell = (stageCount + 1) % 10 + 1
                @pic.show[PIC_STAGE + 0] .pos(REF_X + STAGE_NUM_X + 8 * 0, REF_Y + STAGE_NUM_Y) .topLeft .cell(cell) fontPicCmd
                // /
                @pic.show[PIC_STAGE + 1] .pos(REF_X + STAGE_NUM_X + 8 * 1, REF_Y + STAGE_NUM_Y) .topLeft .cell(_SL) fontPicCmd
                // 最大値
                @pic.show[PIC_STAGE + 2] .pos(REF_X + STAGE_NUM_X + 8 * 2, REF_Y + STAGE_NUM_Y) .topLeft .cell(_0 + MAX_STAGE % 10) fontPicCmd
            } ] )
        }
    }

    //------------------------------------------------------------------------------------
    //終了する
    @label.set "gameEnd"
    bl {
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, TS_MINIGAME, NUM_OF_STR)
        @scr.tint .rgbs(100, 100, 100, 100) .time(1) .wait
    }
}