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


cev[CEV_MAGATOKI_WESTERN] .name("mg_逢魔が時ウェスタン") {

    def {
        NUM_OF_VAR = 128
        NUM_OF_STR = 0
        NUM_OF_PIC = 42

        BASE_LAYER = 6

        PATH_BG_0    = "mw\bg0"
        PATH_BG_1    = "mw\bg1"
        PATH_BG_2    = "mw\bg2"
        PATH_MESSAGE = "mw\me"
        PATH_TARGET  = "mw\ta"
        PATH_FLASH   = "mw\fl"
        PATH_FIRE    = "mw\fi"
        PATH_DAMAGE  = "mw\da"
        PATH_STATUS  = "mw\st"
        PATH_BARREL  = "mw\br"
        PATH_CURSOR  = "mw\cu"
        PATH_GUN     = "mw\gu"

        //ピクチャID
        PIC_HEAD    = 1
        PIC_TAG_ISO = 2//+0_+7
        PIC_BG_0    = 10
        PIC_FLASH   = 11//点滅
        PIC_TAG_0   = 12//+0_+7
        PIC_BG_1    = 20
        PIC_TAG_1   = 21//+0_+7
        PIC_BG_2    = 29
        PIC_FIRE    = 30
        PIC_DAMAGE  = 31
        PIC_STATUS  = 32
        PIC_BARREL  = 33
        PIC_TIME    = 34
        PIC_SCORE   = 35
        PIC_HISCORE = 36
        PIC_ADDSCORE= 37
        PIC_MESSAGE = 38
        PIC_RESULT  = 39
        PIC_CURSOR  = 40
        PIC_GUN     = 41

        //実績
        ACHIEVE_SCORE = 30000

        //定数
        OUT_RANGE        = -320
        CURSOR_SPEED     = 6
        BULLET_MAX       = 6
        TRIGGER_INTERVAL = 16
        RELOAD_INTERVAL  = 8
        EVADE_Y          = 208
        TARGET_WIDTH     = 64
        TARGET_HEIGHT    = 80
        SHOOT_EFF_TIMER  = 8
        SPIN_EFF_TIMER   = 3
        SCORE_MAX        = 999999
        TIMELIMIT_SEC    = 50
        SP_TARGET_ID     = 7

        //的のセル番号
        CELL_CAN    = 14
        CELL_GHOST  = 11
        CELL_ZOMBIE = 1
        CELL_GUNMAN = 7
        CELL_DUEL   = 7
        CELL_DOWN   = 5

        //スクロール
        SCROLL_LEFT = 0
        SCROLL_CENTER
        SCROLL_RIGHT
        SCROLL_NUM

        //表示位置
        SCORE_X = 8
        SCORE_Y = 210
        HISCORE_X = 8
        HISCORE_Y = 224
        STATUS_X = 0
        STATUS_Y = 208
        BARREL_X = 155
        BARREL_Y = 220
        TIMELIMIT_X = 140
        TIMELIMIT_Y = 222

        //操作タイプ
        PLAYER_CTRL_KEY = 0
        PLAYER_CTRL_MOUSE
        
        //シーンの状態
        SCENE_STATE_START = 0
        SCENE_STATE_PHASE
        SCENE_STATE_GAME
        SCENE_STATE_END

        //更新フラグ
        TR_BIT_ADDSCORE  = 1 << 0
        TR_BIT_SCORE     = 1 << 1
        TR_BIT_HISCORE   = 1 << 2
        TR_BIT_EVADE     = 1 << 3
        TR_BIT_DAMAGE    = 1 << 4
        TR_BIT_HIT       = 1 << 5
        TR_BIT_BARREL    = 1 << 6
        TR_BIT_TIMELIMIT = 1 << 7
        TR_BIT_DELETETAG = 1 << 8

        //スコア
        SCORE_CAN    = 100
        SCORE_CAN_SP = 1000
        SCORE_GHOST  = 1000
        SCORE_DUEL_NORMAL  = 200
        SCORE_DUEL_COUNTER = 1000
        SCORE_DUEL_SPECIAL = 2000
        SCORE_GUNMAN = 200
        SCORE_ZOMBIE = 100

        TIME_SPECIAL1 = 5
        TIME_SPECIAL2 = 10
        TIME_NORMAL   = 1
        TIME_DAMAGE   = 5

        //的の種類
        TAG_TYPE_NONE = 0
        TAG_TYPE_CAN
        TAG_TYPE_GHOST
        TAG_TYPE_GUNMAN
        TAG_TYPE_ZOMBIE
        TAG_TYPE_DUEL

        //的の状態
        TAG_STATE_INIT = 0
        TAG_STATE_DELETE
        TAG_STATE_HIT
        TAG_STATE_DOWN
        TAG_STATE_FLASH

        TAG_STATE_ATTACK
        TAG_STATE_1
        TAG_STATE_2
        TAG_STATE_3

        //的の数と構造
        TAG_NUM = 8
        MT_TYPE = 0
        MT_STATE
        MT_TIMER
        MT_PID
        MT_SCALE
        MT_MOVE
        MT_PARAM1
        MT_PARAM2
        SIZE_OF_TAG

        mTagType   = v[pA + MT_TYPE]
        mTagState  = v[pA + MT_STATE]
        mTagTimer  = v[pA + MT_TIMER]
        mTagPId    = v[pA + MT_PID]
        mTagScale  = v[pA + MT_SCALE]
        mTagMove   = v[pA + MT_MOVE]
        mTagParam1 = v[pA + MT_PARAM1]
        mTagParam2 = v[pA + MT_PARAM2]

    }

    defv {
        varHead = TV_MINIGAME
        
        ipt
        pid
        cell
        pA
        iA
        type
        state
        timer
        scale
        move
        col
        ax
        ay
        bx
        by

        sceneState
        sceneTimer
        triggerFlg
        timeLimit
        phaseCnt
        scroll

        score
        addScore
        addTime
        shootCnt
        hitCnt

        numZombie
        numGunman
        numActive
        numLock

        allowAttack
        gunCell
        cursorX
        cursorY
        triggerCnt
        bulletCnt
        fireTimer
        spinTimer
        popupTimer

        tagHead

        varFoot = __id(tagHead) + SIZE_OF_TAG * TAG_NUM

    }

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

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

        //文字列
        scoreStrPicCmd = bl {
            .size(0, 0)
            .font("", 14) .bold
            .spacing(0, 4)
            .skin "" .nobg .noframe .noPadding
            basePicCmd
        }

        //フラッシュ
        flashPicCmd = bl {
            PATH_FLASH
            .pos(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2)
            .center
            .scale(WINDOW_WIDTH / 16 * 100)
            basePicCmd
        }

        //メッセージ
        mesPicCmd = bl {
            PATH_MESSAGE
            .grid(1, 2)
            basePicCmd
        }

        //照準
        cursorPicCmd = bl {
            PATH_CURSOR
            .add
            basePicCmd
        }

        //弾痕
        damagePicCmd = bl {
            PATH_DAMAGE
            .scale(100)
            .grid(2, 1)
            basePicCmd
        }

        //着弾エフェクト
        direPicCmd = bl {
            PATH_FIRE
            .scale(100)
            .grid(4, 1)
            basePicCmd
        }

        //弾数
        barrelPicCmd = bl {
            PATH_BARREL
            .pos(BARREL_X, BARREL_Y)
            .topLeft
            .grid(1, 8)
            basePicCmd
        }

        //銃
        gunPicCmd = bl {
            PATH_GUN
            .bottom
            .grid(4, 2)
            basePicCmd
        }

        //的
        targetPicCmd = bl {
            PATH_TARGET
            .center
            .grid(6, 3)
            basePicCmd
        }
    }

    //----------------------------
    //的のポインタを取得する
    __fn _getTargetPtr $dvDst $id bl {
        v[__id($dvDst)] = __id(tagHead) + ($id) * SIZE_OF_TAG
    }

    //的のメンバ変数を初期化する
    __fn _initHeadMember $ptr $arr bl {
        v[$ptr..$ptr + SIZE_OF_TAG - 1] = $arr
    }

    //的の状態を変える
    __fn _changeTargetState $ptr $state bl {
        v[$ptr + MT_STATE] = $state
        v[$ptr + MT_TIMER] = -1
    }

    //シーンの状態を変える
    __fn _changeSceneState $state bl {
        sceneState = $state
        sceneTimer = -1
    }

    //画面をフラッシュさせる
    __fn _flashScreen $r $g $b $s $time bl {
        @pic.show[PIC_FLASH] .trans(0) .rgbs($r, $g, $b, $s) flashPicCmd
        @pic.move[PIC_FLASH] .relative .pos(0, 0) .scale(0) .trans(100) .keepRgbs .time($time)
    }

    //スコアを加算する
    __fn _addScore $score $time bl {
        bitOn(triggerFlg, TR_BIT_ADDSCORE)
        addScore += $score
        addTime += $time
    }

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

    //------------------------------------------------------------------------------------
    //開始処理
    bl {
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, 0, 0)
        storeAndStopBGM()
        msgBottom()
        
        //ピクチャ初期化
        @pic.show[PIC_BG_0] PATH_BG_0 .pos(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2) .center basePicCmd
        @pic.show[PIC_BG_1] PATH_BG_1 .pos(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2) .center basePicCmd
        @pic.show[PIC_BG_2] PATH_BG_2 .pos(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2) .center basePicCmd

        @pic.show[PIC_MESSAGE] .trans(100) mesPicCmd
        @pic.show[PIC_FLASH] .trans(100) flashPicCmd
        @pic.show[PIC_FIRE] .trans(100) direPicCmd
        @pic.show[PIC_DAMAGE] .trans(100) damagePicCmd
        @pic.show[PIC_GUN] .trans(100) gunPicCmd

        @pic.show[PIC_BARREL] barrelPicCmd
        @pic.show[PIC_STATUS] PATH_STATUS .pos(STATUS_X, STATUS_Y) .topLeft basePicCmd
        @pic.show[PIC_CURSOR] .trans(100) cursorPicCmd

        //的ピクチャ
        @loop TAG_NUM .dst(iA) bl {
            pid = PIC_TAG_ISO + iA
            @pic.show[pid] .pos(OUT_RANGE, OUT_RANGE) .cell(0) targetPicCmd
        }
        //暗転
        fastFadeInTintOnly(1)

        @label.jump "gameLoop"
    }

    //------------------------------------------------------------------------------------
    //ゲーム処理
    @label.set "gameLoop"
    bl {
        //----------------------------
        //初期化
        _changeSceneState(SCENE_STATE_START)
        triggerFlg = TR_BIT_SCORE | TR_BIT_HISCORE | TR_BIT_TIMELIMIT | TR_BIT_BARREL | TR_BIT_DELETETAG

        timeLimit = 0
        phaseCnt = 0
        scroll = SCROLL_CENTER

        score = 0
        addScore = 0
        addTime = 0

        shootCnt = 0
        hitCnt = 0

        numZombie = 0
        numGunman = 0
        numActive = 0
        numLock   = 0

        allowAttack = FALSE
        gunCell = -1
        cursorX = 160
        cursorY = 120
        triggerCnt = 0
        bulletCnt  = BULLET_MAX
        fireTimer  = 0
        spinTimer  = 0
        popupTimer = 0

        //マウスカーソルは下に置く
        @if gameMode == PLAYER_CTRL_MOUSE bl {
            @mouse.setPos(cursorX, cursorY)
        }

        //ピクチャを隠す
        hidePicturesForEach( [PIC_RESULT, PIC_MESSAGE] )

        //背景を元の位置に置く
        @foreach [PIC_BG_0, PIC_BG_1, PIC_BG_2] .dst(pid) {
            @pic.move[pid] .pos(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2)
        }

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

            //----------------------------
            //ポーズ
            pauseProcces(TRUE, ipt, "gameEnd")

            //----------------------------
            //シーン

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

            //ゲーム中
            @if sceneState == SCENE_STATE_GAME bl {
                //カウントダウン
                timeLimit -= 1
                //1秒ごとに更新する
                @if `!(timeLimit % 60) bl {
                    bitOn(triggerFlg, TR_BIT_TIMELIMIT)
                    //制限時間が迫ると音が鳴る
                    @if timeLimit <= UNIT_FPS * 10 bl {
                        @se.play "Cursor2" .opt(60, 120, 50)
                    }
                }

                //時間切れ
                @if timeLimit <= 0 bl {
                    _changeSceneState(SCENE_STATE_END)
                    //射撃を禁止する
                    allowAttack = FALSE
                //的が無い
                } .elif `numGunman + numZombie + numActive <= 0 bl {
                    _changeSceneState(SCENE_STATE_PHASE)
                    //次のフェイズへ
                    //特に意味はないが、最大は99フェイズ
                    phaseCnt = min(phaseCnt + 1, 99)
                //0.5秒ごとに的を追加する
                //numLockが1以上だと出てこなくなる
                } .else bl {
                    @if `numLock <= 0 && !(sceneTimer % 30) bl {
                        //同時出現数
                        //12フェイズごとに増える
                        ipt = clamp(phaseCnt / 12, 1, 3)
                        @loop ipt bl {
                            //種類を選ぶ
                            @if `numZombie > 0 && numGunman > 0 bl {
                                type = rnd(0, 1) ? TAG_TYPE_ZOMBIE : TAG_TYPE_GUNMAN
                            } .elif numZombie > 0 bl {
                                type = TAG_TYPE_ZOMBIE
                            } .elif numGunman > 0 bl {
                                type = TAG_TYPE_GUNMAN
                            } .else bl {
                                //選べなかった
                                @break
                            }

                            //場所をランダムに選ぶ
                            iA = rnd(0, [6, 5, 6][scroll])
                            _getTargetPtr(pA, iA)

                            cell = iA + scroll * 8
                            //picture id, scale, move, x, y
                            //pid = 0-7 or 10-17 10:spcial target
                            pid = [ 0, 1, 2, 3,11,12,13,-1, 
                                    0, 1, 2, 3, 4, 5,-1,-1,
                                    0, 1, 2, 3,11,12, 4,-1][cell]
                            ax  = [ 100,100, 60, 90,200,200,200,100,
                                    100,100,100,100,100,100,100,100,
                                    100,100, 75, 75,200,150, 80,100][cell]
                            ay  = [ 0,0,1,2,3,3,3,0,
                                    0,0,0,0,0,0,0,0,
                                    0,0,2,2,3,1,1,0][cell]
                            bx  = [ 224,224, 64,142, 55,160,270,  0,
                                     64,160,256, 64,160,256,  0,  0,
                                     96, 96,290,230,260, 42,172,  0][cell]
                            by  = [  48,148,155,152,180,180,180,  0,
                                     48, 48, 48,148,148,148,  0,  0,
                                     48,148, 76,160,160,165, 60,  0][cell]

                            //既に使われているか、ピクチャ番号が正しくない
                            @if `mTagType != TAG_TYPE_NONE || !between(pid, 0, 20) bl {
                                @continue
                            }

                            //メンバー変数を設定
                            _initHeadMember(pA, [type, TAG_STATE_INIT, -1, pid + PIC_TAG_0, ax, ay, bx, by] )

                            //カウンタを減らす
                            @if type == TAG_TYPE_ZOMBIE bl {
                                numZombie -= 1
                            } .elif type == TAG_TYPE_GUNMAN bl {
                                numGunman -= 1
                            }
                        }
                    }
                }
            //次のフェイズへ
            } .elif sceneState == SCENE_STATE_PHASE bl {
                $eventFrame1 = 30

                //移動する
                //最初のフェイズの時は省略する
                @if phaseCnt > 0 bl {
                    @if sceneTimer == 0 bl {
                        //的を消す
                        bitOn(triggerFlg, TR_BIT_DELETETAG)
                        //重複しないように
                        scroll = (scroll + 1) % SCROLL_NUM
                        //表示位置
                        V2_set(ax, [320, 160, 0][scroll], 120)
                        //pid,cell
                        $wait = $eventFrame1 / 6
                        @foreach [PIC_BG_0, PIC_BG_1, PIC_BG_2] .dst(pid) {
                            @pic.move [pid] .pos(ax, ay) .center .scale(100) .trans(0) .time($wait)
                        }
                        @se.play "Bow2" .opt(80, 100, 50)
                    }
                }

                //フェイズ開始
                @if sceneTimer >= $eventFrame1 bl {
                    _changeSceneState(SCENE_STATE_GAME)
                    //敵の数を設定する
                    //4フェイズごとに一体ずつ、最大12体
                    //3フェイズごとにガンマンの割合が増えていく
                    bx = min(6 + phaseCnt / 4, 12)
                    numZombie = max(bx - phaseCnt / 3, 0)
                    numGunman = max(bx - numZombie, 0)
                    //2フェイズごとに特殊な的が現れる
                    @if `timeLimit >= UNIT_FPS * 5 && !(phaseCnt % 2) bl {
                        _getTargetPtr(pA, SP_TARGET_ID)
                        //左:缶  中央: 決闘ゾンビ  右:ゴースト 
                        type = [TAG_TYPE_CAN, TAG_TYPE_DUEL, TAG_TYPE_GHOST][scroll]
                        pid = 10
                        V2_set(ax, 100, 0)
                        V2_set(bx,
                            [175, 160, rnd(0, 1) * 320][scroll],
                            [ 48, 150,  64][scroll]
                        )
                        //既に使用されている場合は出現しない
                        @if `mTagType == TAG_TYPE_NONE bl {
                            //メンバー変数を設定
                            _initHeadMember(pA, [type, TAG_STATE_INIT, -1, pid + PIC_TAG_0, ax, ay, bx, by] )
                        } 
                    }
                }
            //開始
            } .elif sceneState == SCENE_STATE_START bl {
                $eventFrame1 = 30
                //撃て！
                @if sceneTimer == 0 bl {
                    @pic.show [PIC_MESSAGE] .pos(160, 240) .center .cell(1) mesPicCmd
                    @pic.move [PIC_MESSAGE] .pos(160, 120) .center .time(4)
                    //時間制限を設定する
                    timeLimit = UNIT_FPS * TIMELIMIT_SEC
                    bitOn(triggerFlg, TR_BIT_TIMELIMIT)
                }

                //撃てるようになるまで猶予がある
                @if sceneTimer == $eventFrame1 bl {
                    allowAttack = TRUE
                }

                //撃った瞬間に始まる
                @if `allowAttack && bulletCnt < BULLET_MAX bl {
                    @pic.move[PIC_MESSAGE] .trans(100)
                    //BGM
                    startBGM("town10", FALSE, 0, 80, 130, 50)

                    _changeSceneState(SCENE_STATE_PHASE)
                }

            //終了
            } .elif sceneState == SCENE_STATE_END bl {
                //文字を表示する
                @if sceneTimer == 0 bl {
                    @pic.show [PIC_MESSAGE] .pos(160, 240) .center .cell(2) mesPicCmd
                    @pic.move [PIC_MESSAGE] .pos(160, 60) .center .time(4)

                    stopBGM(0)
                    @se.play "Bell" .opt(100, 140, 50)
                }

                //スコアを表示する
                @if sceneTimer == 80 bl {
                    //命中率
                    ax = hitCnt * 100 / max(shootCnt, 1)
                    $mes = __str("",
                        "\c[9]HIT:      \c[0]\", hitCnt, NEWLINE,
                        "\c[9]ACCURACY: \c[0]\", ax, " %", NEWLINE,
                        "\c[9]SCORE:    \c[0]\", score
                    )

                    @pic.strpic [PIC_RESULT] $mes .pos(160, 80) .top .rgbs(200, 200, 200, 100) scoreStrPicCmd
                    @pic.move   [PIC_RESULT] .relative .pos(0, 0) .scale(0) .trans(0) .rgbs(100, 100, 100, 100) .time(2)
                    @se.play "register" .opt(80, 100, 50)
                }

                //選択肢を出す前に的を全て消す
                @if sceneTimer == 180 - 1 bl {
                    bitOn(triggerFlg, TR_BIT_DELETETAG)
                }

                //もう一回やる？
                @if sceneTimer >= 180 bl {
                    _updateHighScore()
                    replayProcess("gameLoop", "gameEnd")
                }
            }

            //----------------------------
            //的を全て消す
            @if `triggerFlg & TR_BIT_DELETETAG bl {
                bitOff(triggerFlg, TR_BIT_DELETETAG)
                @loop TAG_NUM .dst(iA) bl {
                    _getTargetPtr(pA, iA)
                    @if `mTagType != TAG_TYPE_NONE bl {
                        _changeTargetState(pA, TAG_STATE_DELETE)
                    }
                }
            }

            //的を更新し、数える
            numActive = 0
            numLock = 0
            @loop TAG_NUM .dst(iA) bl {
                _getTargetPtr(pA, iA)

                type = mTagType
                @if type == TAG_TYPE_NONE bl {
                    @continue
                }

                //カウントアップ
                mTagTimer += 1

                //一時変数
                state  = mTagState
                timer  = mTagTimer
                pid    = mTagPId
                scale  = mTagScale
                move   = mTagMove

                //的ピクチャのIDを移動させる
                @if `state == TAG_STATE_INIT && timer <= 0 bl {
                    bx = PIC_TAG_ISO + iA
                    pid = mTagPId
                    @pic[bx].setId .move(pid, 1)
                }

                //ピクチャの中心位置
                @pic.getInfo [pid] .currentRect(ax, ay, 0, 0) .cewh

                //----------------------------
                //その場で消える
                @if state == TAG_STATE_DELETE bl {
                    //何もしない
                //点滅して消える
                } .elif state == TAG_STATE_FLASH bl {
                    numActive += 1
                    @if timer > 24 bl {
                        _changeTargetState(pA, TAG_STATE_DELETE)

                    } .else bl {
                        bx = (timer % 2) ? 100 : -1
                        @pic.move [pid] .pos(ax, ay) .center .scale(scale) .trans(bx)
                    }

                //ダウン
                } .elif state == TAG_STATE_DOWN bl {
                    numActive += 1
                    @if timer >= 32 bl {
                        _changeTargetState(pA, TAG_STATE_FLASH)

                    } .else bl {
                        @if timer == 0 bl {
                            ay -= 18
                        } .elif `between(timer, 0, 7) bl {
                            ay += 3
                        } .elif `between(timer, 8, 11) bl {
                            ay -= 1
                            @if timer == 8 bl {
                                @se.play "Blow6" .opt(80, 80, 50)
                            }
                        }

                        @pic.move [pid] .pos(ax, ay) .center .scale(scale)
                    }

                //ゾンビ or ガンマン
                } .elif `type == TAG_TYPE_ZOMBIE || type == TAG_TYPE_GUNMAN bl {
                    numActive += 1
                    //初期化
                    @if state == TAG_STATE_INIT bl {
                        cell = (type == TAG_TYPE_GUNMAN) ? CELL_GUNMAN + rnd(1, 3) : CELL_ZOMBIE + rnd(0, 3)
                        //スライド移動
                        V2_set(bx, mTagParam1, mTagParam2)
                        V2_set(ax,
                            bx - [0, 32,-32,  0][move] * scale / 100,
                            by - [0,  0,  0,-40][move] * scale / 100
                        )

                        @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(  0,   0,   0, 100) .cell(cell) targetPicCmd
                        @pic.move [pid] .pos(bx, by) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .time(2)

                        _changeTargetState(pA, TAG_STATE_1)

                    //撃たれた
                    } .elif state == TAG_STATE_HIT bl {
                        cell = CELL_DOWN + rnd(0, 1)
                        @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(200,   0,   0, 100) .cell(cell) targetPicCmd

                        bx = (type == TAG_TYPE_GUNMAN) ? SCORE_GUNMAN : SCORE_ZOMBIE
                        _addScore(bx, TIME_NORMAL)

                        _changeTargetState(pA, TAG_STATE_DOWN)

                    //撃つ
                    } .elif state == TAG_STATE_ATTACK bl {
                        //光る
                        @if timer == 0 bl {
                            @pic.move [pid] .relative .pos(0, 0) .scale(0) .trans(0) .rgbs(200, 200, 200, 100)
                        } .elif timer == 1 bl {
                            @pic.move [pid] .relative .pos(0, 0) .scale(0) .trans(0) .rgbs(100, 100, 100, 100) .time(2)
                        } .elif timer >= 60 bl {
                            _changeTargetState(pA, TAG_STATE_2)
                        }

                    //待機
                    } .elif state == TAG_STATE_1 bl {
                        //戻る
                        bx = 30 + clamp(30 - phaseCnt, 0, 30)
                        @if timer > bx bl {
                            //ガンマンとゾンビで分岐する
                            bx = (type == TAG_TYPE_GUNMAN) ? TAG_STATE_ATTACK : TAG_STATE_2
                            _changeTargetState(pA, bx)
                        }

                    //戻る
                    } .elif state == TAG_STATE_2 bl {
                        @if timer == 0 bl {
                            V2_set(ax,
                                [0, 32,-32,  0][move] * scale / 100 * -1,
                                [0,  0,  0,-40][move] * scale / 100 * -1
                            )
                            @pic.move [pid] .relative .pos(ax, ay) .scale(0) .trans(0) .rgbs(  0,   0,   0, 100) .time(2)

                        } .elif timer >= 6 * 2 bl {
                            //カウンタを戻す
                            @if type == TAG_TYPE_ZOMBIE bl {
                                numZombie += 1
                            } .elif type == TAG_TYPE_GUNMAN bl {
                                numGunman += 1
                            }
                            _changeTargetState(pA, TAG_STATE_DELETE)
                        }
                    }

                //ゴースト
                } .elif type == TAG_TYPE_GHOST bl {
                    numActive += 1
                    //初期化
                    @if state == TAG_STATE_INIT bl {
                        //出現時間はランダム
                        @if `(rnd(0, 99) <= 20 || timer >= 180) && !(timer % 30) bl {
                            cell = CELL_GHOST + 0
                            //位置
                            V2_set(ax, mTagParam1, mTagParam2)
                            ax = (ax - 160) > 0 ? 320 + 24 : 0 - 24
                            @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .cell(cell) targetPicCmd
                            //移動速度
                            mTagParam1 = (ax - 160) > 0 ? -2 : 2
                            mTagParam2 = 0

                            _changeTargetState(pA, TAG_STATE_1)
                        }

                    //撃たれた
                    } .elif state == TAG_STATE_HIT bl {
                        cell = CELL_GHOST + 2
                        @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .cell(cell) targetPicCmd

                        _addScore(SCORE_GHOST, TIME_SPECIAL2)
                        _changeTargetState(pA, TAG_STATE_FLASH)

                        @se.play "bell1" .opt(100, 80, 50)

                    //通常
                    } .elif state == TAG_STATE_1 bl {
                        //上下に揺れる
                        ax += mTagParam1
                        ay += sin(timer * 6 + 90, 1, 3)
                        //画面端に消える
                        @if `!between(ax, 0 - 32, WINDOW_WIDTH + 32) bl {
                            _changeTargetState(pA, TAG_STATE_DELETE)

                        } .else bl {
                            //アニメーション
                            @if `!(timer % 4) bl {
                                cell = (timer % 8 < 4) ? CELL_GHOST + 0 : CELL_GHOST + 1
                                @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .cell(cell) targetPicCmd
                            } .else bl {
                                @pic.move [pid] .pos(ax, ay) .scale(scale) .trans(0)
                            }
                        }
                    }

                //缶
                } .elif type == TAG_TYPE_CAN bl {
                    //初期化
                    @if state == TAG_STATE_INIT bl {
                        cell = CELL_CAN + 0
                        V2_set(ax, mTagParam1, mTagParam2)
                        @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .cell(cell) targetPicCmd

                        //体力の代わりにする
                        mTagMove = 6

                        _changeTargetState(pA, TAG_STATE_1)

                    //撃たれた
                    } .elif state == TAG_STATE_HIT bl {
                        numActive += 1

                        //移動速度
                        mTagParam1 = rnd(-1, 1)
                        mTagParam2 = -4

                        //体力
                        mTagMove -= 1

                        //６回撃つと消える
                        @if `mTagMove > 0 bl {
                            _addScore(SCORE_CAN, TIME_SPECIAL1)
                            _changeTargetState(pA, TAG_STATE_2)
                            @se.play "can1" .opt(100, 100, 50)
                        } .else bl {
                            _addScore(SCORE_CAN_SP, TIME_SPECIAL1)
                            _changeTargetState(pA, TAG_STATE_FLASH)
                            @se.play "itemget2" .opt(100, 120, 50)
                        }

                    //通常
                    } .elif state == TAG_STATE_1 bl {
                        //何もしない
                    //落下しながら落ちる
                    } .elif state == TAG_STATE_2 bl {
                        //落下中はフェイズが移動しない
                        numActive += 1
                        //移動
                        ax += mTagParam1
                        ay += mTagParam2
                        //画面端にぶつかると反射する
                        @if `!between(ax, 0 + 8, WINDOW_WIDTH - 8) bl {
                            ax = clamp(ax, 0 + 8 + 1, WINDOW_WIDTH - 8 - 1)
                            mTagParam1 *= -1
                        }
                        //落下
                        @if `!(timer % 8) bl {
                            mTagParam2 += 1
                        }
                        //着地
                        @if `ay > 180 bl {
                            cell = CELL_CAN + 0
                            ay = 180

                            _changeTargetState(pA, TAG_STATE_FLASH)

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

                        //回転アニメーション
                        @if `!(timer % 4) bl {
                            cell = CELL_CAN + 1 + (timer / 4) % 4
                            @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .cell(cell) targetPicCmd
                        } .else bl {
                            @pic.move [pid] .pos(ax, ay) .scale(scale) .trans(0)
                        }
                    }

                //決闘ゾンビ
                } .elif type == TAG_TYPE_DUEL bl {
                    //出現中は他のゾンビが出てこない
                    numActive += 1
                    numLock += 1
                    //初期化
                    @if state == TAG_STATE_INIT bl {
                        //暗がりから現れる
                        cell = CELL_DUEL + 0

                        V2_set(ax, mTagParam1, mTagParam2)
                        V2_set(bx, ax, ay - 4)

                        @pic.show [pid] .pos(bx, by) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .cell(cell) targetPicCmd
                        @pic.move [pid] .pos(ax, ay) .scale(scale) .trans(0) .time(2)

                        //パラメータを初期化する
                        mTagMove   = 0
                        mTagParam1 = 0
                        mTagParam2 = 0

                        _changeTargetState(pA, TAG_STATE_1)

                        @se.play "Move" .opt(70, 100, 50)

                    //撃たれた
                    } .elif state == TAG_STATE_HIT bl {
                        //吹っ飛ぶ
                        @if timer == 0 bl {
                            cell = CELL_DOWN + 1
                            @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .cell(cell) targetPicCmd

                            //銃が抜かれてから撃つと高得点
                            //抜かれた際、カーソルが下にあるとさらに高得点
                            bx = mTagParam1
                            @if bx == 1 bl {
                                bx = SCORE_DUEL_COUNTER
                                by = TIME_SPECIAL2

                                @se.play "jet" .opt(100, 100, 50)

                            } .elif bx == 2 bl {
                                bx = SCORE_DUEL_SPECIAL
                                by = TIME_SPECIAL2

                                @se.play "Flash1" .opt(100, 100, 50)

                            } .else bl {
                                bx = SCORE_DUEL_NORMAL
                                by = TIME_SPECIAL1
                            }
                            _addScore(bx, by)
                        }
                        _changeTargetState(pA, TAG_STATE_DOWN)

                    //射撃
                    } .elif state == TAG_STATE_ATTACK bl {
                        //消える
                        @if timer == 60 bl {
                            @pic.move [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(0, 0, 0, 100) .time(2)
                        } .elif timer == 60 + 6 * 2 bl {
                            _changeTargetState(pA, TAG_STATE_DELETE)
                        }

                    //通常
                    } .elif state == TAG_STATE_1 bl {
                        //1.5秒以上で20fごとに判定する。最大で4秒
                        @if `timer >= 90 && timer % 20 == 0 && (rnd(0, 1) || timer >= 240) bl {
                            _changeTargetState(pA, TAG_STATE_2)
                        }

                    //構え
                    } .elif state == TAG_STATE_2 bl {
                        //引き抜く
                        @if timer == 0 bl {
                            cell = CELL_DUEL + 1
                            @pic.show [pid] .pos(ax, ay) .scale(scale) .trans(0) .rgbs(100, 100, 100, 100) .cell(cell) targetPicCmd

                            //カーソルが下にあると得点が増える
                            mTagParam1 = (cursorY > EVADE_Y) ? 2 : 1

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

                        //射撃(猶予は24f)
                        @if timer >= 24 bl {
                            mTagParam1 = 0
                            _changeTargetState(pA, TAG_STATE_ATTACK)
                        }
                    }
                }

                //射撃
                @if `allowAttack && state == TAG_STATE_ATTACK && timer == 0 bl {
                    @if cursorY > EVADE_Y bl {
                        //回避成功
                        bitOn(triggerFlg, TR_BIT_EVADE)
                    } .else bl {
                        //直撃
                        bitOn(triggerFlg, TR_BIT_DAMAGE)
                    }

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

                //的を消去する
                @if state == TAG_STATE_DELETE bl {
                    //ピクチャを控えに置く
                    bx = PIC_TAG_ISO + iA
                    @pic[pid].setId .move(bx, 1)
                    @pic.move[bx] .pos(OUT_RANGE, OUT_RANGE) .scale(100) .trans(100)

                    mTagType = TAG_TYPE_NONE
                }
            }

            //----------------------------
            //照準
            @if gameMode == PLAYER_CTRL_KEY bl {
                V2_getInput(ax)
                V2_asMulScalar(ax, CURSOR_SPEED)
                V2_asAdd(cursorX, ax)
            } .else bl {
                //マウスカーソルが画面外にあっても入力する
                @mouse.getPos(ax, ay)
                V2_copy(cursorX, ax)
            }

            //拘束
            V2_set(cursorX,
                clamp(cursorX, 0, WINDOW_WIDTH),
                clamp(cursorY, 0, WINDOW_HEIGHT)
            )
            //ゲーム終了後は少し透明になる
            bx = allowAttack ? 0 : 50 
            //ピクチャの位置
            @pic.show[PIC_CURSOR] .pos(cursorX, cursorY) .center .trans(bx) cursorPicCmd

            //----------------------------
            //引き金
            @if gameMode == PLAYER_CTRL_KEY bl {
                @key.input .dst(ipt) .decision
            } .else bl {
                @key.input .dst(ipt) .lclick
            }

            triggerCnt = ipt ? triggerCnt + 1 : 0

            //----------------------------
            //射撃
            //ゲーム開始時かゲーム中かつ、スピンしていない時のみ撃てる
            @if `allowAttack && spinTimer <= 0 bl {
                //入力カウント
                bx = triggerCnt - 1
                //画面下にカーソルを置くとリロードする
                @if cursorY > EVADE_Y bl {
                    //一発ずつ込める
                    @if `bulletCnt < BULLET_MAX && !(bx % RELOAD_INTERVAL) bl {
                        bitOn(triggerFlg, TR_BIT_BARREL)

                        bulletCnt += 1

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

                //射撃
                } .elif `!(bx % TRIGGER_INTERVAL) bl {
                    //弾切れ
                    @if bulletCnt <= 0 bl {
                        @se.play "trigger1" .opt(100, 100, 50)
                    //発射
                    } .else bl {
                        bitOn(triggerFlg, TR_BIT_BARREL)
                        //射撃回数
                        shootCnt += 1
                        //弾薬消費
                        bulletCnt -= 1
                        //発射エフェクト
                        fireTimer = SHOOT_EFF_TIMER
                        @pic.show [PIC_FIRE] .pos(cursorX, cursorY) .rangeAnim(SHOOT_EFF_TIMER / 4, 1, 4) .add direPicCmd
                        //銃声
                        @se.play "gun3" .opt(100, 100, 50)
                        //地形との衝突判定
                        ipt = 0
                        @foreach [PIC_BG_2, PIC_BG_1] .dst(pid) {
                            @pic.getInfo [pid] .currentRect(ax, ay, bx, by) .xywh
                            V2_sub(ax, cursorX, ax)
                            @if `bx > 0 && by > 0 && between(ax, 0, bx - 1) && between(ay, 0, by - 1) {
                                //拡縮には対応していない
                                //ピクセルを取得する(argb)
                                @pic.getInfo [pid] .pixel(ax,ay, 1, 1) .dst(cell) .static
                                //透明でない場合、衝突したと見なす
                                @if `cell & 0xff000000 0 bl {
                                    ipt = pid
                                    @break
                                }
                            }
                        }
                        //的との衝突判定
                        @loop TAG_NUM .dst(iA) bl {
                            _getTargetPtr(pA, iA)
                            //的のピクチャ番号
                            pid = mTagPid
                            //状態が条件を満たさないか、当たった地形よりも奥にある場合、衝突判定を行わない
                            @if `mTagType == TAG_TYPE_NONE || mTagState <= TAG_STATE_FLASH || pid < ipt bl {
                                @continue
                            }
                            @pic.getInfo [pid] .currentRect(ax, ay, bx, by) .xywh
                            V2_sub(ax, cursorX, ax)
                            @if `bx > 0 && by > 0 && between(ax, 0, bx - 1) && between(ay, 0, by - 1) {
                                //拡縮に対応しているが、回転には未対応
                                V2_set(ax,
                                    ax * TARGET_WIDTH  / bx,
                                    ay * TARGET_HEIGHT / by
                                )
                                @pic.getInfo [pid] .pixel(ax,ay, 1, 1) .dst(cell) .static
                                @if `cell & 0xff000000 0 bl {
                                    bitOn(triggerFlg, TR_BIT_HIT)
                                    hitCnt += 1
                                    _changeTargetState(pA, TAG_STATE_HIT)

                                }
                            }
                        }
                    }
                }
            }

            //----------------------------
            //銃ピクチャ
            @if gameMode == PLAYER_CTRL_KEY bl {
                @key.input .dst(ipt) .shift
            } .else bl {
                @key.input .dst(ipt) .rclick
            }

            //ピクチャの位置
            V2_set(ax,
                lerp(150, 360, cursorX, WINDOW_WIDTH),
                lerp(250, 320, cursorY, WINDOW_HEIGHT)
            )

            //銃の色
            col = 100
            //セル番号
            cell = -1

            //通常 / スピン
            @if `ipt || spinTimer > 0 bl {
                $time = (SPIN_EFF_TIMER * 10)

                ay  += [30, 15, 0, -15, -15, 0, 15, 15, -15, 0][spinTimer / SPIN_EFF_TIMER]
                cell = [3, 3, 4, 5, 6, 7, 8, 3, 2, 2][spinTimer / SPIN_EFF_TIMER]

                spinTimer += 1

                //効果音
                @if spinTimer == SPIN_EFF_TIMER * 3 bl {
                    @se.play "Wind7" .opt(50, 80, 50)
                }

                //回転継続
                @if `ipt && spinTimer == SPIN_EFF_TIMER * 7 bl {
                    spinTimer = SPIN_EFF_TIMER * 2
                }

                //停止
                @if spinTimer >= SPIN_EFF_TIMER * 10 bl {
                    spinTimer = 0
                }

            } .else bl {
                cell = (fireTimer > 0) ? 2 : 1
                //射撃直後
                @if fireTimer > 0 bl {
                    ay += lerp(0, -10, fireTimer, SHOOT_EFF_TIMER)
                    col = lerp(100, 200, fireTimer, SHOOT_EFF_TIMER)
                }
            }

            //セル番号を変える
            @if `cell > 0 && cell != gunCell bl {
                gunCell = cell
                @pic.show[PIC_GUN] .pos(ax, ay) .scale(100) .trans(0) .cell(cell) .rgbs(col, col, col, col) gunPicCmd
            } .else bl {
                @pic.move [PIC_GUN] .pos(ax, ay) .bottom .scale(100) .trans(0) .rgbs(col, col, col, col)
            }

            //射撃直後
            @if fireTimer > 0 bl {
                fireTimer -= 1
                //着弾エフェクトを消す
                @if fireTimer <= 0 bl {
                    @pic.show [PIC_FIRE] .trans(100) .cell(1) direPicCmd
                }
            }

            //----------------------------
            //ステータスバー
            //画面下にカーソルを置くと色が変わる
            V2_set(ax, (cursorY > EVADE_Y) ? 200 : 100, 100)
            @pic.move [PIC_STATUS] .relative .pos(0, 0) .scale(0) .trans(0) .rgbs(ax, ax, ax, ay)

            //----------------------------
            //加算スコアの表示
            @if popupTimer > 0 bl {
                popupTimer -= 1
                @if popupTimer <= 0 bl {
                    @pic.move[PIC_ADDSCORE] .trans(100)
                }
            }

            //----------------------------
            //フラグ消化
            @if `triggerFlg bl {
                //----------------------------
                //ダメージ
                @if `triggerFlg & TR_BIT_DAMAGE bl {
                    bitOff(triggerFlg, TR_BIT_DAMAGE)
                    //減点
                    //無敵モード中は減らない
                    @if invincibleSwitch.isOff bl {
                        timeLimit = max(timeLimit - TIME_DAMAGE * UNIT_FPS, 0)
                    }

                    bitOn(triggerFlg, TR_BIT_TIMELIMIT)

                    //画面の点滅
                    _flashScreen(200, 0, 0, 100, 1)
                    //弾痕を表示する
                    ax = rnd(160 - 80, 160 + 80)
                    ay = rnd(120 - 40, 120 + 40)
                    @pic.show[PIC_DAMAGE] .pos(ax, ay) .center .trans(-500) .cell(1) damagePicCmd
                    @pic.move[PIC_DAMAGE] .relative .pos(0, 0) .scale(0) .trans(600) .time(10)
                    //画面揺れ
                    @scr.shake .once(1) .value(5, 7)
                    //効果音
                    ax = rnd(10, 12) * 10
                    @se.play "voice_aa" .opt(100, ax, 50)
                    @se.play "Damage1" .opt(80, 80, 50)
                }

                //回避
                @if `triggerFlg & TR_BIT_EVADE bl {
                    bitOff(triggerFlg, TR_BIT_EVADE)
                    //弾痕を表示する
                    ax = cursorX + rnd(-16, 16)
                    ay = 240 - 32
                    @pic.show[PIC_DAMAGE] .pos(ax, ay) .center .trans(-500) .cell(2) damagePicCmd
                    @pic.move[PIC_DAMAGE] .relative .pos(0, 0) .scale(0) .trans(600) .time(5)
                    @se.play "gun3" .opt(100, 150, 50)
                }

                //命中
                @if `triggerFlg & TR_BIT_HIT bl {
                    bitOff(triggerFlg, TR_BIT_HIT)
                    _flashScreen(100, 100, 100, 100, 1)
                }

                //スコアを加算し、文字列を表示する
                @if `triggerFlg & TR_BIT_ADDSCORE bl {
                    bitOff(triggerFlg, TR_BIT_ADDSCORE)
                    bitOn(triggerFlg, TR_BIT_SCORE | TR_BIT_TIMELIMIT)
                    //ピクチャを表示する
                    popupTimer = 60
                    V2_set(ax, cursorX, cursorY - 8)
                    @pic.strpic[PIC_ADDSCORE] __str("\c[2]\",addScore, " \c[7]\", addTime, "s") .pos(ax, ay) .scale(100) .trans(0) scoreStrPicCmd
                    @pic.move[PIC_ADDSCORE] .relative .pos(0, -8) .scale(0) .trans(0) .time(2)

                    score = clamp(score + addScore, 0, SCORE_MAX)
                    timeLimit = clamp(timeLimit + addTime * UNIT_FPS, 0, TIMELIMIT_SEC * UNIT_FPS)

                    addScore = 0
                    addTime  = 0

                    //実績
                    checkSetAchievement(achievedWestern, score >= ACHIEVE_SCORE)
                }

                //スコアを表示する
                @if `triggerFlg & TR_BIT_SCORE bl {
                    bitOff(triggerFlg, TR_BIT_SCORE)
                    @pic.strpic [PIC_SCORE] __str("\c[7]1P \c[4]\", score) .pos(SCORE_X, SCORE_Y) .topLeft .scale(100) .trans(0) scoreStrPicCmd
                }

                //ハイスコアを表示する
                @if `triggerFlg & TR_BIT_HISCORE bl {
                    bitOff(triggerFlg, TR_BIT_HISCORE)
                    @pic.strpic [PIC_HISCORE] __str("\c[7]HI \c[4]\", magatokiWesternScore) .pos(HISCORE_X, HISCORE_Y) .topLeft .scale(100) .trans(0) scoreStrPicCmd
                }

                //残り時間を表示する
                @if `triggerFlg & TR_BIT_TIMELIMIT bl {
                    bitOff(triggerFlg, TR_BIT_TIMELIMIT)
                    //横に伸縮する
                    bx = timeLimit / UNIT_FPS
                    @pic.strpic [PIC_TIME] __str("\c[7]\", bx) .pos(TIMELIMIT_X, TIMELIMIT_Y) .top .scale2(20, 100) .trans(0) scoreStrPicCmd
                    @pic.move [PIC_TIME] .relative .pos(0, 0) .scale2(80, 0) .trans(0) .time(1)
                }

                //弾数を表示する
                @if `triggerFlg & TR_BIT_BARREL bl {
                    bitOff(triggerFlg, TR_BIT_BARREL)
                    //排莢直後だとリロードの文字が消える
                    cell = clamp(bulletCnt + 1, 1, 8)
                    @pic.show [PIC_BARREL] .cell(cell) barrelPicCmd
                }

                //ハイスコアを表示する
                @if `triggerFlg & TR_BIT_HISCORE bl {
                    bitOff(triggerFlg, TR_BIT_HISCORE)
                    @pic.strpic [PIC_HISCORE] __str("\c[7]HI \c[4]\", magatokiWesternScore) .pos(HISCORE_X, HISCORE_Y) .topLeft .scale(100) .trans(0) scoreStrPicCmd
                }
            }
        }
    }

    //------------------------------------------------------------------------------------
    //終了する
    @label.set "gameEnd"
    bl {
        _updateHighScore()

        //ピクチャ、変数を初期化
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, 0, 0)
        restoreBGM()
        fastFadeInTintOnly(1)
    }
}