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


cev[CEV_JEWEL_TOWER] .name("mg_ジュエルタワー") {

    def {
        NUM_OF_VAR = 256
        NUM_OF_STR = 0
        NUM_OF_PIC = 90

        BASE_LAYER = 6

        PATH_BACK   = "jt\ba"
        PATH_LOGO   = "jt\lo"
        PATH_GAUGE  = "jt\ga"
        PATH_LINE   = "jt\li"
        PATH_BLOCK  = "jt\bl"
        PATH_COUNT  = "jt\co"
        PATH_PLAYER = "jt\pl"

        PIC_HEAD     = 1
        PIC_BACK     = 2
        PIC_LINE     = 3//+0_+1
        PIC_FIELD    = 5//+0_+54
        PIC_HAND     = 60//+0_+1
        PIC_NEXT     = 62//+0_+1
        PIC_PLAYER   = 65
        PIC_SCORE    = 66//+0_+4
        PIC_HISCORE  = 71//+0_+4
        PIC_TIME     = 76//+0_+2
        PIC_COMBO    = 79//+0_+1
        PIC_GAUGE    = 81//+0_+1
        PIC_ADDSCORE = 83//+0_+4
        PIC_LOGO     = 88

        //実績
        ACHIEVE_SCORE = 7000

        //トリガー
        TR_BIT_SCORE    = 1 << 0
        TR_BIT_HISCORE  = 1 << 1
        TR_BIT_TIME     = 1 << 2
        TR_BIT_COMBO    = 1 << 3
        TR_BIT_ADDSCORE = 1 << 4
        TR_BIT_NEXT     = 1 << 5
        TR_BIT_PLAYER   = 1 << 6

        //シーン
        SCENE_START = 0
        SCENE_TIMEUP
        SCENE_GAMEOVER
        SCENE_RETRY
        SCENE_NEXT
        SCENE_MOVE
        SCENE_CHECK
        SCENE_DELETE

        //ブロック
        //color 1_4
        //reach 5
        //search id 9-16
        CHIP_NONE = 0
        CHIP_RED
        CHIP_YELLOW
        CHIP_GREEN
        CHIP_BLUE
        CHIP_COLOR_MASK = 0xf
        CHIP_LIGHTUP = 0x10

        //定数
        OUT_RANGE = -320
        INPUT_REPEAT = 6
        TIME_SECONDS = 120
        COUNTER_WIDTH = 8
        CONNECT_NUM = 5
        PATTERN_NUM = 6

        FIELD_X = 128
        FIELD_Y = 24
        FIELD_WIDTH  = 5
        FIELD_HEIGHT = 11

        CHIP_NUM     = 55//@loopで使用する
        CHIP_WIDTH   = 16

        PLAYER_X = (128 + 8)
        PLAYER_Y = 218

        HISCORE_X = 288
        HISCORE_Y = 64

        SCORE_X = 288
        SCORE_Y = 88
        SCORE_DIGIT = 5
        SCORE_MAX   = 99999

        ADDSCORE_X = 288
        ADDSCORE_Y = 32
        ADDSCORE_DIGIT = 5

        TIME_X = 288
        TIME_Y = 112
        TIME_DIGIT = 3

        COMBO_X = 288
        COMBO_Y = 136
        COMBO_DIGIT = 2
        COMBO_MAX = 16
        COMBO_MULTI = 5

        GAUGE_X = 224
        GAUGE_Y = 128
        GAUGE_WIDTH = 48
        GAUGE_TIME = 300

        NEXT_X = 224
        NEXT_Y = 40

        CHK_PLAYER_MOVEABLE = between(sceneState, SCENE_NEXT, SCENE_DELETE)
        CHK_MOVE  = (!((iptHCounter - 1) % INPUT_REPEAT))
        CHK_SWAP  = ((iptShift == 1) || (iptV > 0 && iptVCounter == 1))
        CHK_SHOOT = ((iptDec >= 1) || (iptV < 0 && iptVCounter >= 1))

    }

    def {
        basePicCmd = {
            .chromakey(1)
            .mapLayer(BASE_LAYER)
            .eraseWhenTransfer
            .affectedByFlash
            .affectedByShake
        }

        //カウンタ
        countPicCmd = {
            PATH_COUNT
            .grid(10, 1)
            basePicCmd
        }

        //ロゴ
        logoPicCmd = {
            PATH_LOGO
            .grid(1, 3)
            basePicCmd
        }

        //落下予測
        linePicCmd = {
            PATH_LINE
            .grid(4, 1)
            basePicCmd
        }

        //ゲージエフェクト
        gaugePicCmd = {
            PATH_GAUGE
            .grid(5, 1)
            basePicCmd
        }

        //ブロック
        blockPicCmd = {
            PATH_BLOCK
            .grid(4, 4)
            basePicCmd
        }

        //プレイヤー
        playerPicCmd = {
            PATH_PLAYER
            .grid(2, 2)
            basePicCmd
        }

    }

    defv {
        varHead = TV_MINIGAME
        
        ipt
        pid
        cell
        idx
        time
        count
        ground
        stackId
        targetId
        idxNumA
        idxNumB
        blockA
        blockB
        colorA
        colorB
        ix
        iy
        sx
        sy
        ex
        ey
        ax
        ay
        ftA

        initHead//初期化対象の先頭

        triggerFlg
        sceneState
        sceneTimer

        score
        timeLimit
        gaugeTimer
        addScore
        comboCnt
        patternIdx

        iptH
        iptHCounter
        iptV
        iptVCounter
        iptDec
        iptShift

        stackNum
        playerCell
        playerX
        next0
        next1
        hand0
        hand1
        handX0
        handX1

        patternArr
        fieldArr  = (__id(patternArr) + PATTERN_NUM)
        stackArr  = (__id(fieldArr) + CHIP_NUM)
        varFoot = (__id(stackArr) + CHIP_NUM)
    }

    commentRangeOfVariables(varFoot, TV_MINIGAME, NUM_OF_VAR, NUM_OF_STR, NUM_OF_PIC)

    //----------------------------
    //座標から番号を取得する
    __fn _getIndexFromPost $dvDst $x $y bl {
        v[__id($dvDst)] = ($x) * FIELD_HEIGHT + ($y)
    }

    //マスの中央の座標を取得する
    __fn _V2_getBlockPos $dvDst $idx bl {
        v[__id($dvDst)..__id($dvDst) + 1] = [ FIELD_X + ($idx) / FIELD_HEIGHT * CHIP_WIDTH,
        FIELD_Y + ($idx) % FIELD_HEIGHT * CHIP_WIDTH + (($idx) / FIELD_HEIGHT % 2) * CHIP_WIDTH / 2 ]
    }

    //数値を表示する
    __fn _showCounter $num $pid $dig $x $y bl {
        iy = 1
        @loop $dig .dst(ix) bl {
            v[__id(sx)..__id(sy)] = [($x) - ix * COUNTER_WIDTH, ($y)]
            pid  = ($pid) + ix
            cell = (($num) < iy && iy != 1) ? (0) : (1 + ($num) % (iy * 10) / iy)
            @pic.show [pid] .pos(sx, sy) .topRight .scale(100) .cell(cell) countPicCmd  
            //次の桁
            iy *= 10
        }
    }

    //スタックにデータを積む
    __fn _pushStack $id $idx bl {
        v[__id(stackArr) + stackNum] = ((($idx) & 0xff) << 8) | (($id) & 0xff)
        stackNum += 1
    }
    
    //スタックからデータを取得する
    __fn _popStack $dvId $dvIdx bl {
        stackNum -= 1
        ftA = v[__id(stackArr) + stackNum]
        v[__id($dvId)] = ftA & 0xff
        v[__id($dvIdx)] = (ftA >> 8) & 0xff
    }

    //スタックを初期化する
    __fn _initStack bl {
        stackNum = 0
    }

    //背景を光らせる
    __fn _flashBackGround $time bl {
        @pic.show [PIC_BACK] PATH_BACK .pos(0, 0) .topLeft .rgbs(160, 160, 160, 100) basePicCmd
        @pic.move [PIC_BACK] .relative .pos(0, 0) .scale(0) .trans(0) .rgbs(100, 100, 100, 100) .time($time)
    }

    //ハイスコアを更新する
    __fn _updateHighScore bl {
        jewelTowerScore = max(jewelTowerScore, score)
    }

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

    //------------------------------------------------------------------------------------
    //開始処理
    bl {
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, TS_MINIGAME, NUM_OF_STR)
        msgBottom()
        
        @scr.tint .rgbs(30, 30, 30, 100) .time(1)
        //ピクチャ
        @pic.show [PIC_BACK] PATH_BACK .pos(0, 0) .topLeft basePicCmd
        @pic.show [PIC_LOGO] .pos(OUT_RANGE, OUT_RANGE) .center .cell(0) logoPicCmd
        @pic.show [PIC_PLAYER] .pos(OUT_RANGE, OUT_RANGE) .center .cell(0) playerPicCmd
        @pic.show [PIC_GAUGE + 0] .pos(OUT_RANGE, OUT_RANGE) .center .trans(100) .cell(1) gaugePicCmd
        @pic.show [PIC_GAUGE + 1] .pos(OUT_RANGE, OUT_RANGE) .center .trans(100) .rangeAnim(4, 2, 5) gaugePicCmd

        @loop 2 .dst(idx) bl {
            pid = PIC_HAND + idx
            @pic.show [pid] .pos(OUT_RANGE, OUT_RANGE) .cell(0) blockPicCmd
            pid = PIC_NEXT + idx
            @pic.show [pid] .pos(OUT_RANGE, OUT_RANGE) .cell(0) blockPicCmd
            pid = PIC_LINE + idx
            @pic.show [pid] .pos(OUT_RANGE, OUT_RANGE) .cell(0) linePicCmd
        }

        @loop CHIP_NUM .dst(pid) bl {
            pid += PIC_FIELD
            @pic.show [pid] .pos(OUT_RANGE, OUT_RANGE) .cell(0) blockPicCmd
        }

        @wait(1)
        @label.jump "gameLoop"
    }

    //------------------------------------------------------------------------------------
    //ゲーム処理
    @label.set "gameLoop"
    bl {
        //ピクチャを初期化する
        @pic.move [PIC_PLAYER] .pos(320/2, 240 + 32) .center .trans(100)
        @loop 2 .dst(idx) bl {
            pid = PIC_HAND + idx
            @pic.move [pid] .pos(320/2, 240 + 32) .trans(100)
            pid = PIC_LINE + idx
            @pic.move [pid] .pos(320/2, 240 + 32) .trans(100)
        }

        @loop 2 .dst(idx) bl {
            pid = PIC_GAUGE + idx
            @pic.move [pid] .pos(OUT_RANGE, OUT_RANGE) .trans(100)
        }

        @loop SCORE_DIGIT .dst(idx) bl {
            pid = PIC_ADDSCORE + idx
            @pic.move [pid] .pos(OUT_RANGE, OUT_RANGE) .trans(100)
        }

        //変数を一括で初期化する
        assignVarUsingDeclared(initHead, varFoot, 0)

        _setSceneState(SCENE_START)
        triggerFlg = TR_BIT_SCORE | TR_BIT_HISCORE | TR_BIT_TIME | TR_BIT_COMBO | TR_BIT_PLAYER | TR_BIT_NEXT
        timeLimit = UNIT_FPS * TIME_SECONDS

        playerX = FIELD_WIDTH / 2
        playerCell = 1
        copyToArray(handX0, 2, [ playerX + 0, playerX + 1 ] )

        //最初は固定
        copyToArray(hand0, 2, [ 1, 2 ] )
        copyToArray(next0, 2, [ 3, 4 ] )

        //パターンは6個
        copyToArray(patternArr, PATTERN_NUM,
        [ 1<<8 | 2, 1<<8 | 3, 1<<8 | 4, 2<<8 | 3,
          2<<8 | 4, 3<<8 | 4 ]
        )
        
        //同色の組み合わせを含む10種類
        //copyToArray(patternArr, PATTERN_NUM,
        //[ 1<<8 | 1, 2<<8 | 2, 3<<8 | 3, 4<<8 | 4,
        //  1<<8 | 2, 1<<8 | 3, 1<<8 | 4, 2<<8 | 3,
        //  2<<8 | 4, 3<<8 | 4 ]
        //)

        //パターンをシャッフル
        patternArr.shuffle(PATTERN_NUM + 1)

        //最初に上3列に敷き詰める
        @loop 3 .dst(iy) bl {
            @loop FIELD_WIDTH .dst(ix) bl {
                blockA = 1 + iy % 2 * 2 + ix % 2
                _getIndexFromPost(idxNumA, ix, iy)
                writeToArray(blockA, fieldArr, idxNumA)
            }
        }

        //ブロックのピクチャを敷く
        @loop CHIP_NUM .dst(idx) bl {
            readFromArray(blockA, fieldArr, idx)
            _V2_getBlockPos(sx, idx)
            blockA = v[__id(fieldArr) + idx]
            colorA = blockA & CHIP_COLOR_MASK
            pid   = PIC_FIELD + idx
            cell = colorA
            @pic.show [pid] .pos(sx, sy) .center .cell(cell) blockPicCmd
        
        }

        //----------------------------
        //ループ
        @loop bl {
            @wait(0)

            //----------------------------
            //ポーズ
            @key.input .dst(ipt) .cancel
            
            //メニューを開くとコンボが途切れる直前になる
            //タイマーも一秒ずつ減っていく
            @if `ipt bl {
                gaugeTimer = min(gaugeTimer, 1)
                @if timeLimit > 1 bl {
                    bitOn(triggerFlg, TR_BIT_TIME)
                    timeLimit = max(timeLimit - UNIT_FPS, 1)
                }
            }

            pauseProcces(FALSE, ipt, "gameEnd")

            //----------------------------
            //入力
            @key.input .dst(ipt) .decision
            iptDec = ipt ? iptDec + 1 : 0
            @key.input .dst(ipt) .shift
            iptShift = ipt ? iptShift + 1 : 0
            @key.input .dst(ipt) {
                .left
                .right
            }
            iptH = ipt == KEY_LEFT ? -1 : 1
            iptHCounter = ipt ? iptHCounter + 1 : 0
            @key.input .dst(ipt) {
                .up
                .down
            }
            iptV = ipt == KEY_UP ? -1 : 1
            iptVCounter = ipt ? iptVCounter + 1 : 0

            //----------------------------
            //シーン
            //カウントアップ
            sceneTimer += 1

            //----------------------------
            //移動
            @if sceneState == SCENE_MOVE bl {
                //プレイヤーの移動処理は下に移す
            //----------------------------
            //スタート
            } .elif sceneState == SCENE_START bl {
                @if sceneTimer == 0 bl {
                    @pic.show [PIC_LOGO] .pos(160, 240 + 32) .center .cell(1) logoPicCmd
                    @pic.move [PIC_LOGO] .pos(160, 120 + 32) .center .time(-20)
                    @se.play "Flash1" .opt(100, 80, 50)
                }

                @if sceneTimer == 60 bl {
                    _setSceneState(SCENE_NEXT)
                    @pic.move[PIC_LOGO] .pos(OUT_RANGE, OUT_RANGE) .trans(100)
                }

            //----------------------------
            //タイムアップ
            } .elif sceneState == SCENE_TIMEUP bl {
                @if sceneTimer == 0 bl {
                    _flashBackGround(4)
                    @se.play "Bell" .opt(100, 120, 50)
                }

                @if sceneTimer == 40 bl {
                    @pic.show [PIC_LOGO] .pos(160, 240 + 32) .center .cell(2) logoPicCmd
                    @pic.move [PIC_LOGO] .pos(160, 120 - 32) .center .time(-20)
                    @se.play "Holy9" .opt(100, 100, 50)

                    //プレイヤーのパターンを変更
                    bitOn(triggerFlg, TR_BIT_PLAYER)
                    playerCell = 4
                }

                //ピースを消す
                @if sceneTimer >= 40 bl {
                    idxNumA = (sceneTimer - 40)
                    @if `between(idxNumA, 0, CHIP_NUM - 1) bl {
                        readFromArray(cell, fieldArr, idxNumA)
                        @if cell != CHIP_NONE bl {
                            pid = PIC_FIELD + idxNumA
                            @pic.getInfo [pid] .currentRect(sx, sy, 0, 0) .cewh 
                            @pic.move[pid] .pos(sx, sy) .scale(100) .trans(100) .time(-4)
                        }
                    }
                }

                @if sceneTimer >= 180 bl {
                    _setSceneState(SCENE_RETRY)
                }

            //----------------------------
            //ゲームオーバー
            } .elif sceneState == SCENE_GAMEOVER bl {
                @if sceneTimer == 0 bl {
                    _flashBackGround(4)
                    @se.play "Thunder10" .opt(100, 80, 50)
                }

                @if sceneTimer == 40 bl {
                    @pic.show [PIC_LOGO] .pos(160, 240 + 32) .center .cell(3) logoPicCmd
                    @pic.move [PIC_LOGO] .pos(160, 120 - 32) .center .time(-20)
                    @se.play "register" .opt(100, 50, 50)
                    //プレイヤーのパターンを変更
                    bitOn(triggerFlg, TR_BIT_PLAYER)
                    playerCell = 3
                }

                //ピースを落とす
                @if sceneTimer >= 40 bl {
                    ix = (sceneTimer - 40) / 5
                    @if `between(ix, 0, FIELD_WIDTH - 1) bl {
                        @loop FIELD_HEIGHT .dst(iy) bl {
                            idxNumA = ix * FIELD_HEIGHT + iy
                            readFromArray(cell, fieldArr, idxNumA)
                            @if cell != CHIP_NONE bl {
                                pid = PIC_FIELD + idxNumA
                                @pic.getInfo [pid] .currentRect(sx, sy, 0, 0) .cewh
                                sy += 240
                                @pic.move[pid] .pos(sx, sy) .scale(100) .trans(100) .time(-40)
                            }
                        }
                    }
                }

                @if sceneTimer >= 180 bl {
                    _setSceneState(SCENE_RETRY)
                }

            //選択肢を出す
            } .elif sceneState == SCENE_RETRY bl {
                _updateHighScore()
                replayProcess("gameLoop", "gameEnd")
            //次
            } .elif sceneState == SCENE_NEXT bl {
                //無敵モード中だと、最下段２つが常に消える
                @if invincibleSwitch.isOn bl {
                    @loop 2 .dst(iy) bl {
                        iy = FIELD_HEIGHT - 1 - iy
                        @loop FIELD_WIDTH .dst(ix) bl {
                            _getIndexFromPost(idxNumA, ix, iy)
                            readFromArray(blockA, fieldArr, idxNumA)
                            colorA = blockA & CHIP_COLOR_MASK
                            @if colorA != CHIP_NONE bl {
                                writeToArray(CHIP_NONE, fieldArr, idxNumA)

                                pid = PIC_FIELD + idxNumA
                                @pic.move [pid] .pos(OUT_RANGE, OUT_RANGE) .trans(100)
                            }
                        }
                    }
                }

                //ゲームオーバー判定
                ground = FALSE//フラグ
                iy = FIELD_HEIGHT - 1
                @loop FIELD_WIDTH .dst(ix) bl {
                    _getIndexFromPost(idxNumA, ix, iy)
                    readFromArray(blockA, fieldArr, idxNumA)
                    colorA = blockA & CHIP_COLOR_MASK

                    @if colorA != CHIP_NONE bl {
                        ground = TRUE
                        @break
                    }
                }

                //ゲームオーバー
                @if `ground bl {
                    _setSceneState(SCENE_GAMEOVER)
                //時間切れ
                } .elif timeLimit <= 0 bl {
                    _setSceneState(SCENE_TIMEUP)
                //次の操作を待つ
                } .else bl {
                    _setSceneState(SCENE_MOVE)
                    //プレイヤーのパターン
                    bitOn(triggerFlg, TR_BIT_PLAYER)
                    playerCell = 1
                    @se.play "Attack2" .opt(60, 100, 50)
                }

            //----------------------------
            //連結判定
            } .elif sceneState == SCENE_CHECK bl {
                //最初のフレーム
                @if sceneTimer == 0 bl {
                    //判定用のビットを初期化する
                    @loop CHIP_NUM .dst(idxNumA) bl {
                        readFromArray(blockA, fieldArr, idxNumA)
                        blockA &= 0xff
                        writeToArray(blockA, fieldArr, idxNumA)
                    }
                }

                //1fにスタックデータを16個消化する
                @loop 16 bl {
                    @if stackNum <= 0 bl {
                        @break
                    }
                    //IDと判定番号を取得する
                    _popStack(stackId, idxNumA)
                    //マス情報を取得
                    readFromArray(blockA, fieldArr, idxNumA)
                    targetId = (blockA >> 8) & 0xff
                    colorA = blockA & CHIP_COLOR_MASK
                    //既に調査されているマスはスルーする
                    @if targetId == 0 bl {
                        //IDを入力する
                        blockA |= (stackId & 0xff) << 8
                        writeToArray(blockA, fieldArr, idxNumA)
                        //6方向を調べ、同じ色だった場合はスタックにデータを積む
                        //X軸が奇数か偶数で調べる位置が変わる
                        //中心マス
                        V2_set(sx,
                            idxNumA / FIELD_HEIGHT,
                            idxNumA % FIELD_HEIGHT
                        )
                        //(右下,下,左下,左上,上,右上)
                        @loop 6 .dst(ground) bl {
                            //奇数
                            @if `sx % 2 bl {
                                V2_set(ix,
                                    sx + [1, 0, -1, -1, 0, 1][ground],
                                    sy + [1, 1, 1, 0, -1, 0][ground]
                                )
                            //偶数
                            } .else bl {
                                V2_set(ix,
                                    sx + [1, 0, -1, -1, 0, 1][ground],
                                    sy + [0, 1, 0, -1, -1, -1][ground]
                                )
                            }

                            //判定すべきマスが範囲内にある
                            @if `between(ix, 0, FIELD_WIDTH - 1) &&
                                between(iy, 0, FIELD_HEIGHT - 1) bl {
                                
                                idxNumB = ix * FIELD_HEIGHT + iy

                                readFromArray(blockB, fieldArr, idxNumB)
                                targetId = (blockB >> 8) & 0xff
                                colorB = blockB & CHIP_COLOR_MASK

                                //まだ判定してないかつ、色が同じかつ、スタック数が限度未満
                                @if `targetId == 0 && colorA == colorB && stackNum < CHIP_NUM bl {
                                    _pushStack(stackId, idxNumB)
                                }
                            }
                        }
                    }
                }

                //スタックデータを全て消化した
                @if stackNum <= 0 bl {
                    //数F待つ
                    @if sceneTimer >= 8 bl {
                        //次のブロック
                        _setSceneState(SCENE_NEXT)
                        //リーチ
                        count = 0
                        //1から始まるIDごとのマス数を数える
                        //スタック用の配列を流用する
                        initArray(stackArr, CHIP_NUM, 0)
                        @loop CHIP_NUM .dst(idxNumA) bl {
                            readFromArray(blockA, fieldArr, idxNumA)
                            targetId = (blockA >> 8) & 0xff
                            v[__id(stackArr) + targetId] += 1
                        }

                        //連結数が規定数を超えた塊をリーチ状態にする
                        @loop CHIP_NUM .dst(idxNumA) bl {
                            //idxNumA : ID
                            ground = v[__id(stackArr) + idxNumA]
                            //0番目は除く
                            //ID=0は初期値だからだ
                            @if `idxNumA > 0 && ground >= CONNECT_NUM bl {
                                count += 1
                                @loop CHIP_NUM .dst(idxNumB) bl {
                                    readFromArray(blockB, fieldArr, idxNumB)
                                    targetId = (blockB >> 8) & 0xff
                                    colorB = blockB & CHIP_COLOR_MASK
                                    @if targetId == idxNumA bl {
                                        @if `blockB & CHIP_LIGHTUP bl {
                                            //既に光っている
                                        } .else bl {
                                            //光らせる
                                            blockB |= CHIP_LIGHTUP
                                            writeToArray(blockB, fieldArr, idxNumB)
                                            //ピクチャを置き換える
                                            pid = PIC_FIELD + idxNumB
                                            ex = 4 + 1 + (colorB - 1) * 2
                                            ey = ex + 1
                                            _V2_getBlockPos(sx, idxNumB)

                                            @pic.show [pid] .pos(sx, sy) .center .scale(150) .rangeAnim(8, ex, ey) .rgbs(200, 200, 200, 100) blockPicCmd
                                            @pic.move [pid] .relative .pos(0, 0) .scale(-50) .trans(0) .rgbs(100, 100, 100, 100) .time(-16)
                                        }
                                    }
                                }
                            }
                        }

                        //判定用のビットを初期化する
                        @loop CHIP_NUM .dst(idxNumA) bl {
                            readFromArray(blockA, fieldArr, idxNumA)
                            blockA &= 0xff
                            writeToArray(blockA, fieldArr, idxNumA)
                        }

                        //一つでも繋がると消えない
                        @if count > 0 bl {
                            _setSceneState(SCENE_NEXT)
                            //コンボ継続
                            @if comboCnt > 0 bl {
                                gaugeTimer = GAUGE_TIME
                            }
                            @se.play "money2" .opt(100, 100, 50)
                            @se.play "Barrier" .opt(100, 120, 50)

                        //一つも繋がらなかった場合、消去する
                        } .else bl {
                            _setSceneState(SCENE_DELETE)
                        }
                    }
                }

            //----------------------------
            //光っている石を全て消す
            } .elif sceneState == SCENE_DELETE bl {
                @if sceneTimer == 0 bl {
                    //消去数
                    count = 0
                    //色数
                    time = 0
                    //色数ビット
                    colorB = 0
                    //消滅演出とカウント
                    @loop CHIP_NUM .dst(idxNumA) bl {
                        readFromArray(blockA, fieldArr, idxNumA)
                        colorA = blockA & CHIP_COLOR_MASK
                        @if `blockA & CHIP_LIGHTUP bl {
                            //消去数
                            count += 1
                            //色数を数える
                            @if `colorB & (1 << colorA) bl {
                            } .else bl {
                                time += 1
                                colorB |= (1 << colorA)
                            }
                            pid = PIC_FIELD + idxNumA
                            _V2_getBlockPos(sx, idxNumA)
                            @pic.show [pid] .pos(sx, sy) .center .scale(100) .trans(0) .rangeAnim(5, 13, 16) .add blockPicCmd
                        }
                    }

                    //消える石が一つもない場合、即座に次のブロックを補充する
                    @if count <= 0 bl {
                        _setSceneState(SCENE_NEXT)
                    } .else bl {
                        bitOn(triggerFlg, TR_BIT_SCORE | TR_BIT_COMBO | TR_BIT_ADDSCORE)
                        //コンボゲージ
                        gaugeTimer = GAUGE_TIME
                        comboCnt = clamp(comboCnt + 1, 0, COMBO_MAX)
                        //スコア加算
                        //消した数 * コンボ数 * 色数 * 係数
                        addScore = count * comboCnt * time * COMBO_MULTI
                        score = clamp(score + addScore, 0, SCORE_MAX)
                        //実績
                        checkSetAchievement(achievedJewel, score >= ACHIEVE_SCORE)
                        //ランダムな効果音
                        ground = rnd(0, 5)
                        __loop [ bl { @se.play "Explosion4" .opt(100, 100, 50) },
                        bl { @se.play "Holy2" .opt(100, 100, 50) },
                        bl { @se.play "Ice10" .opt(100, 100, 50) },
                        bl { @se.play "Water2" .opt(100, 100, 50) },
                        bl { @se.play "Earth2" .opt(100, 100, 50) },
                        bl { @se.play "Fire3" .opt(100, 100, 50) } ] $block $idx bl {
                            @if ground == $idx bl {
                                $block
                            }
                        }
                    }
                }

                //落下させる
                @if sceneTimer == 20 bl {
                    //消した部分を掃除する
                    @loop CHIP_NUM .dst(idxNumA) bl {
                        readFromArray(blockA, fieldArr, idxNumA)
                        @if `blockA & CHIP_LIGHTUP bl {
                            writeToArray(0, fieldArr, idxNumA)

                            pid = PIC_FIELD + idxNumA
                            _V2_getBlockPos(sx, idxNumA)
                            @pic.show [pid] .pos(sx, sy) .center .trans(100) .cell(0) blockPicCmd
                        }
                    }

                    //上から下へ
                    count = 0
                    idx = 1//スタックデータに付与するID
                    @loop FIELD_WIDTH .dst(ix) bl {
                        ground = 0
                        @loop FIELD_HEIGHT .dst(iy) bl {
                            idxNumA = ix * FIELD_HEIGHT + iy
                            readFromArray(blockA, fieldArr, idxNumA)
                            //ブロックがある
                            @if blockA != CHIP_NONE bl {
                                //落とす位置
                                idxNumB = ix * FIELD_HEIGHT + ground
                                //落とす必要があるか
                                @if iy > ground bl {
                                    //書き換え
                                    writeToArray(0, fieldArr, idxNumA)
                                    writeToArray(blockA, fieldArr, idxNumB)
                                    //ピクチャを隠す
                                    _V2_getBlockPos(sx, idxNumA)
                                    _V2_getBlockPos(ex, idxNumB)
                                    pid = PIC_FIELD + idxNumA
                                    @pic.show [pid] .pos(sx, sy) .center .trans(100) .cell(0) blockPicCmd

                                    //延びる
                                    time = (iy - ground) * 2 * -1

                                    V2_set(ax,
                                        100,
                                        (sy - ey) * 100 / CHIP_WIDTH
                                    )
                                    V2_set(sx,
                                        sx,
                                        (sy + ey) / 2
                                    )

                                    pid = PIC_FIELD + idxNumB
                                    cell = blockA
                                    @pic.show [pid] .pos(sx, sy) .center .scale2(ax, ay) .cell(cell) blockPicCmd
                                    @pic.move [pid] .pos(ex, ey) .center .scale2(100, 100) .time(time)

                                    //落ちた個数
                                    count += 1
                                    //スタックにデータを積む
                                    _pushStack(idx, idxNumB)
                                    idx += 1
                                    //次の地面
                                    ground += 1

                                } .else bl {
                                    //次の地面
                                    ground = iy + 1
                                }

                                //地面が天井を越えているならループ終わり
                                @if ground >= FIELD_HEIGHT bl {
                                    @break
                                }
                            }
                        }
                    }

                    //落下音
                    @if count > 0 bl {
                        @se.play "Barrier2" .opt(80, 100, 50)
                    }
                }

                @if sceneTimer == 24 bl {
                    _setSceneState(SCENE_CHECK)
                }
            }

            //----------------------------
            //プレイヤー操作 / タイマー
            @if `CHK_PLAYER_MOVEABLE bl {
                //ゲームタイマー
                @if timeLimit > 0 bl {
                    timeLimit -= 1
                    @if `timeLimit % UNIT_FPS == 0 bl {
                        bitOn(triggerFlg, TR_BIT_TIME)
                        //カウントダウン効果音
                        @if `between(timeLimit / UNIT_FPS, 1, 10) bl {
                            @se.play "Cursor2" .opt(60, 100, 50)
                        }
                    }
                }

                //ゲージ
                @if gaugeTimer > 0 bl {
                    gaugeTimer -= 1
                    //コンボが途切れる
                    @if gaugeTimer <= 0 bl {
                        bitOn(triggerFlg, TR_BIT_COMBO)
                        comboCnt = 0

                        @pic.move [PIC_GAUGE + 0] .pos(OUT_RANGE, OUT_RANGE) .trans(100)
                        @pic.move [PIC_GAUGE + 1] .pos(OUT_RANGE, OUT_RANGE) .trans(100)
                        @se.play "Ice2" .opt(60, 80, 50)

                    } .else bl {
                        V2_set(sx,
                            GAUGE_X,
                            GAUGE_Y - gaugeTimer * GAUGE_WIDTH / GAUGE_TIME / 2
                        )
                        V2_set(ex,
                            20,
                            100 * gaugeTimer * GAUGE_WIDTH / GAUGE_TIME / 16
                        )
                        @pic.move [PIC_GAUGE + 0] .pos(sx, sy) .center .scale2(ex, ey) .center

                        V2_set(sx,
                            GAUGE_X,
                            GAUGE_Y - gaugeTimer * GAUGE_WIDTH / GAUGE_TIME
                        )
                        @pic.move [PIC_GAUGE + 1] .pos(sx, sy) .center
                    }
                }

                //プレイヤーの移動
                @if `CHK_MOVE bl {
                    bitOn(triggerFlg, TR_BIT_PLAYER)

                    idx = playerX
                    playerX = clamp(playerX + iptH, 0, FIELD_WIDTH - 2)

                    handX0 =  clamp(handX0 + playerX - idx, 0, FIELD_WIDTH - 1)
                    handX1 =  clamp(handX1 + playerX - idx, 0, FIELD_WIDTH - 1)
                }

                //ブロックを交換する
                @if `CHK_SWAP bl {
                    bitOn(triggerFlg, TR_BIT_PLAYER)
                    //交換する
                    idx = handX0
                    handX0 = handX1
                    handX1 = idx

                    @se.play "trigger1" .opt(80, 50, 50)
                }

                //ブロックを射出する
                //シーンによって制限される
                @if `CHK_SHOOT && sceneState == SCENE_MOVE bl {
                    bitOn(triggerFlg, TR_BIT_PLAYER | TR_BIT_NEXT)
                    _setSceneState(SCENE_CHECK)
                    playerCell = 2

                    @se.play "Blow4" .opt(80, 110, 50)
                    @se.play "jet" .opt(60, 100, 50)

                    //スタックを初期化する
                    _initStack()
                    //叩きつける
                    @loop 2 .dst(idx) bl {
                        //X軸
                        ix = v[__id(handX0) + idx]
                        //落下地点を探す
                        ground = 0
                        @loop FIELD_HEIGHT .dst(iy) bl {
                            iy = (FIELD_HEIGHT - 1) - iy
                            _getIndexFromPost(idxNumA, ix, iy)
                            readFromArray(blockA, fieldArr, idxNumA)

                            //何かあると、その一段下を返す
                            @if `blockA > 0 bl {
                                ground = iy + 1
                                @break
                            }
                        }

                        _getIndexFromPost(idxNumA, ix, ground)

                        //入力するブロックの色
                        colorA = v[__id(hand0) + idx]
                        //ピクチャ
                        //延びるように移動する
                        _V2_getBlockPos(ex, idxNumA)

                        V2_set(sx,
                            ex,
                            (PLAYER_Y - 16 + ey) / 2
                        )

                        V2_set(ax,
                            100,
                            ((PLAYER_Y - 16) - ey) * 100 / 16
                        )

                        pid = PIC_FIELD + idxNumA
                        cell = colorA
                        @pic.show [pid] .pos(sx, sy) .center .scale2(ax, ay) .cell(cell) blockPicCmd
                        @pic.move [pid] .pos(ex, ey) .center .scale2(100, 100) .time(-2)
                        //入力する
                        writeToArray(colorA, fieldArr, idxNumA)
                        //判定の起点
                        //判定ID(0:未入力)
                        cell = idx + 1
                        _pushStack(cell, idxNumA)
                    }

                    //次のブロックを用意する
                    @loop 2 .dst(idx) bl {
                        //手持ちのブロック
                        v[__id(hand0) + idx] = v[__id(next0) + idx]
                        //反転も初期化する
                        v[__id(handX0) + idx] = playerX + idx
                    }

                    //次のブロックをセットする
                    readFromArray(colorA, patternArr, patternIdx)
                    next0 = (colorA >> 8) & 0xff
                    next1 = (colorA) & 0xff

                    //左右反転
                    next0.shuffle(2 + 1)

                    //シャッフル
                    patternIdx += 1
                    @if patternIdx >= PATTERN_NUM bl {
                        patternArr.shuffle(PATTERN_NUM + 1)
                        patternIdx = 0

                    }

                    //手持ちのピクチャをプレイヤーの位置に移動させる
                    @pic.getInfo [PIC_PLAYER] .currentRect(sx, sy, 0, 0) .cewh 
                    @loop 2 .dst(idx) bl {
                        pid = PIC_HAND + idx
                        @pic.show [pid] .pos(sx, sy) .center .cell(0) blockPicCmd
                    }
                }
            }

            //----------------------------
            //トリガー
            @if `triggerFlg bl {
                //スコア
                @if `triggerFlg & TR_BIT_SCORE bl {
                    bitOff(triggerFlg, TR_BIT_SCORE)
                    _showCounter(score, PIC_SCORE, SCORE_DIGIT, SCORE_X, SCORE_Y)
                }

                //ハイスコア
                @if `triggerFlg & TR_BIT_HISCORE bl {
                    bitOff(triggerFlg, TR_BIT_HISCORE)
                    _showCounter(jewelTowerScore, PIC_HISCORE, SCORE_DIGIT, HISCORE_X, HISCORE_Y)
                }

                //タイムリミット
                @if `triggerFlg & TR_BIT_TIME bl {
                    bitOff(triggerFlg, TR_BIT_TIME)
                    ax = timeLimit / UNIT_FPS
                    _showCounter(ax, PIC_TIME, TIME_DIGIT, TIME_X, TIME_Y)
                }

                //コンボ
                @if `triggerFlg & TR_BIT_COMBO bl {
                    bitOff(triggerFlg, TR_BIT_COMBO)
                    _showCounter(comboCnt, PIC_COMBO, COMBO_DIGIT, COMBO_X, COMBO_Y)
                }

                //獲得スコア
                @if `triggerFlg & TR_BIT_ADDSCORE bl {
                    bitOff(triggerFlg, TR_BIT_ADDSCORE)
                    //左から右へ動く
                    _showCounter(addScore, PIC_ADDSCORE, ADDSCORE_DIGIT, ADDSCORE_X - 16, ADDSCORE_Y)
                    @loop SCORE_DIGIT .dst(idx) bl {
                        pid = PIC_ADDSCORE + idx
                        @pic.move [pid] .relative .pos(16, 0) .scale(0) .trans(0) .time(-8)
                    }
                }

                //プレイヤーのピクチャを更新する
                @if `triggerFlg & TR_BIT_PLAYER bl {
                    bitOff(triggerFlg, TR_BIT_PLAYER)
                    V2_set(ex,
                        PLAYER_X + playerX * CHIP_WIDTH,
                        PLAYER_Y
                    )
                    cell = playerCell
                    @pic.getInfo [PIC_PLAYER] .currentRect(sx, sy, 0, 0) .cewh
                    @pic.show [PIC_PLAYER] .pos(sx, sy) .cell(cell) playerPicCmd
                    @pic.move [PIC_PLAYER] .pos(ex, ey) .time(-4)

                    //手持ちのピクチャを更新する
                    @loop 2 .dst(idx) bl {
                        cell = v[__id(hand0) + idx]
                        ix = v[__id(handX0) + idx]

                        V2_set(ex,
                            FIELD_X + CHIP_WIDTH * ix,
                            PLAYER_Y - CHIP_WIDTH 
                        )

                        pid = PIC_HAND + idx
                        @pic.getInfo [pid] .currentRect(sx, sy, 0, 0) .cewh
                        @pic.show [pid] .pos(sx, sy) .cell(cell) blockPicCmd
                        @pic.move [pid] .pos(ex, ey) .time(-4)

                        //落下予測
                        pid = PIC_LINE + idx
                        @if `between(cell, 1, 4) bl {
                            V2_set(ex,
                                FIELD_X + CHIP_WIDTH * ix,
                                120
                            )
                            @pic.show [pid] .pos(ex, ey) .scale2(100, 1300) .trans(80) .cell(cell) .add linePicCmd

                        //透明にする
                        } .else bl {
                            @pic.move [pid] .pos(OUT_RANGE, OUT_RANGE) .trans(100)
                        }
                    }
                }

                //次のブロックのピクチャを更新する
                @if `triggerFlg & TR_BIT_NEXT bl {
                    bitOff(triggerFlg, TR_BIT_NEXT)
                    @loop 2 .dst(idx) bl {
                        readFromArray(cell, next0, idx)
                        V2_set(sx,
                            NEXT_X + CHIP_WIDTH * idx,
                            NEXT_Y + 8
                        )

                        pid = PIC_NEXT + idx
                        @pic.show [pid] .pos(sx, sy) .cell(cell) blockPicCmd
                        @pic.move [pid] .relative .pos(0, -8) .scale(0) .trans(0) .time(-8)
                    }
                }
            }
        }
    }

    //------------------------------------------------------------------------------------
    //終了する
    @label.set "gameEnd"
    bl {
        //ハイスコアを更新する
        _updateHighScore()

        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
    }
}