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


cev[CEV_HANTAS_STORY] .name("mg_ハーたん愛の物語") bl {
    //理論上の最高得点は26,500くらいか？

    //ステージデータ
    //待ち時間(*100),タイプ(-1:待機 2:BAT),x,y,z(*10)
    def {
        STR_STAGE1 = "
40,-1
20,2,-20,0,5
20,2,20,2,5
5,2,-20,-6,5
20,2,-20,-6,5
5,2,20,6,5
30,2,20,6,5
0,2,20,4,5
20,2,15,0,5
0,2,-20,0,5
20,2,-15,-4,5
0,2,20,0,5
40,2,15,-4,5
5,2,25,0,5
5,2,15,4,5
40,2,20,-6,5
5,2,-20,0,5
5,2,-20,-4,5
40,2,-15,6,5
40,5,0,0,200
0,5,6,0,200
40,5,-6,0,200
0,5,6,6,200
40,5,-6,-6,200
5,2,20,-2,5
10,2,-20,4,5
20,5,2,2,200
5,2,20,4,5
10,2,-20,-4,5
40,5,-6,6,200
50,6,-10,-10,200
5,5,-6,6,200
5,5,-0,6,200
30,5,6,6,200
5,5,6,-6,200
5,5,-0,-6,200
40,5,-6,-6,200
5,2,20,2,5
5,2,20,2,5
30,2,20,2,5
5,2,-20,-2,5
5,2,-20,-2,5
30,2,-20,-2,5
0,5,7,7,200
20,5,-7,-7,200
0,5,-7,7,200
20,5,7,-7,200
10,2,20,0,5
10,2,20,0,5
10,2,20,0,5
10,2,20,0,5
20,2,20,0,5
10,2,-20,4,5
10,2,-20,4,5
10,2,-20,4,5
10,2,-20,4,5
20,2,-20,4,5
40,6,-10,10,200
"
        STR_STAGE2 = "
40,-1
20,4,-4,35,45
20,4,4,35,40
20,4,0,35,35
20,4,-2,35,30
40,4,2,35,25
10,4,-4,30,30
30,4,4,30,25
10,4,2,30,25
30,4,4,35,30
20,3,-1,0,200
20,3,1,0,200
10,4,-2,35,40
10,4,-6,30,35
10,4,-2,35,30
10,4,-6,30,25
10,4,2,35,40
10,4,6,30,35
10,4,2,35,30
40,4,6,30,25
0,3,0,-1,200
0,3,2,1,200
30,3,-2,1,200
0,3,0,-1,200
0,3,2,1,200
30,3,-2,1,200
0,4,-4,30,40
10,4,4,30,40
40,6,10,10,200
5,3,1,0,200
5,3,1,0,200
5,3,1,0,200
30,3,1,0,200
5,3,0,1,200
5,3,0,1,200
5,3,0,1,200
5,3,0,1,200
5,3,0,1,200
40,3,0,1,200
5,3,0,-1,200
5,3,0,-1,200
5,3,0,-1,200
5,3,0,-1,200
5,3,0,-1,200
40,3,0,-1,200
0,3,0,-1,200
0,3,0,1,200
40,5,0,-6,200
10,4,-4,20,35
20,5,-4,6,200
10,4,4,20,35
40,5,4,6,200
0,3,0,-1,200
40,3,0,1,200
5,4,0,35,45
5,4,1,35,35
5,4,-1,35,30
40,4,1,35,25
10,5,-7,4,200
10,5, 7,-4,200
50,6,10,10,200
"

        STR_STAGE3 = "
40,-1
5,2,-20,4,5
20,2,-20,4,5
5,2,20,-4,5
30,2,20,-4,5
20,6,-10,10,200
45,6,10,10,200
10,5,6,6,200
10,5,-6,6,200
10,5,6,-6,200
30,5,-6,-6,200
5,2,-20,-6,5
5,2,-25,2,5
5,2,-20,0,5
30,2,-20,-4,5
20,6,10,-10,200
50,6,10,10,200
5,3,0,1,200
5,3,0,1,200
20,3,0,1,200
10,5,0,0,200
5,3,0,-1,200
5,3,0,-1,200
30,3,0,-1,200
20,6,0,-12,200
50,6,0,12,200
10,4,4,30,45
10,4,-5,35,35
10,4,-3,30,30
30,4,2,35,25
5,2,20,-6,5
5,2,25,2,5
30,2,20,-4,5
10,4,-4,30,25
30,4,-5,35,35
10,5,0,6,200
10,5,6,0,200
10,5,0,-6,200
30,5,-6,0,200
0,4,4,28,45
20,4,4,35,35
0,4,-4,28,45
30,4,-4,35,35
2,3,1,0,200
2,3,1,0,200
20,3,1,0,200
2,3,-1,0,200
2,3,-1,0,200
20,3,-1,0,200
10,4,-4,30,25
10,4, 0,25,25
10,4,-4,30,25
10,4, 0,25,25
15,6,-10,-5,200
15,6,-10,10,200
15,6,10,5,200
15,6,-5,10,200
15,6,10,5,200
15,6,10,-10,200
"

    }

    def {
        NUM_OF_VAR = 400
        NUM_OF_STR = 8
        NUM_OF_PIC = 72

        BASE_LAYER = 6

        PATH_DUMMY  = "cm\du"//共通ピクチャ
        PATH_FRAME  = "hs\fr"
        PATH_LIFE   = "hs\li"
        PATH_TINT   = "cm\da"
        PATH_DIST   = "hs\di"
        PATH_CURSOR = "hs\cu"
        PATH_BACK   = "hs\ba"
        PATH_GOAL   = "hs\go"
        PATH_ENDING = "hs\ed"
        PATH_WALL   = "hs\wa"
        PATH_GROUND = "hs\gr"
        PATH_PLAYER = "hs\ha"
        PATH_BULLET = "hs\bu"
        PATH_ENEMY  = "hs\en"

        PIC_HEAD     = 1
        PIC_SORTED_SPRITES = 10//+0_+23
        PIC_SPRITES_HEADER = 34//+0_+23
        PIC_OP_WALL  = 60
        PIC_OP_HARPY = 61
        PIC_LIFE     = 62
        PIC_DIST     = 63
        PIC_CURSOR   = 64
        PIC_TINT     = 65
        PIC_ENDING   = 66
        PIC_SCORE    = 67
        PIC_HISCORE  = 68
        PIC_EVENT    = 69
        PIC_FRAME    = 70

        //
        HT_ACHIEVE_COUNT = 19000

        //更新フラグ
        TR_BIT_SCORE         = 1 << 0
        TR_BIT_HISCORE       = 1 << 1
        TR_BIT_DIST          = 1 << 2
        TR_BIT_LIFE          = 1 << 3
        TR_BIT_PLAYER_ANIM   = 1 << 4
        TR_BIT_PLAYER_DAMAGE = 1 << 5

        //ゲームの状態
        SCENE_STATE_OPENING = 0
        SCENE_STATE_GAME
        SCENE_STATE_DOWN
        SCENE_STATE_GOAL
        SCENE_STATE_GAMEOVER

        //スコア
        SCORE_RUN   = 20
        SCORE_SPEED = 11
        SCORE_ENEMY = 100

        //定数
        UNIT_ANGLE = 10
        UNIT_LOOP = (360 * UNIT_ANGLE)//一回転
        STAGE_MAX = 2
        STAGE_LENGTH = 100000
        STAGE_INTERVAL = 1000
        SCORE_X = 64
        SCORE_Y = 40
        HISCORE_X = 176
        HISCORE_Y = 40
        DIST_X = 44
        DIST_Y = 188
        LIFE_X = 136
        LIFE_Y = 188
        SCROLL_BASE_VZ = 30
        SCROLL_ADD_VZ  = 8
        CAMERA_BASE_RX = (10 * UNIT_ANGLE)
        CAMERA_BASE_Y  = -40
        BACK_Y = 0
        BACK_Z = (SPR_MAX_Z - 1)
        GROUND_X = 160
        GROUND_SCALE = 700
        GOAL_Y = 80
        GOAL_SCALE = 500

        //自機
        PLAYER_POS_MAX = 80
        PLAYER_POS_Z = 150
        PLAYER_ACC_LIMIT = 1
        PLAYER_LIFE = 4
        PLAYER_DAMAGE = 32
        PLAYER_RAD = 18
        PLAYER_SHOOT_WAIT = 8
        PLAYER_SHOOT_VZ = 50
        PLAYER_SHOOT_RAD = 32
        PLAYER_SHOOT_SCA = 100

        //操作タイプ
        PLAYER_CTRL_NORMAL = 0
        PLAYER_CTRL_REVERSE

        //自機のアニメーション
        PLAYER_ANIM_NEUTRAL = 0
        PLAYER_ANIM_SLIDE
        PLAYER_ANIM_DOWN
        PLAYER_ANIM_UP
        PLAYER_ANIM_DAMAGE

        //敵
        ENEMY_MAX_POS = 2000
        ENEMY_MAX_TIME = (60 * 8)
        ENEMY_SHOOT_VZ = 5

        //敵のタイプ
        ENEMY_TYPE_EXPLOSION = 0
        ENEMY_TYPE_BULLET
        ENEMY_TYPE_BAT
        ENEMY_TYPE_GHOST
        ENEMY_TYPE_MERMAN
        ENEMY_TYPE_GRIFFON
        ENEMY_TYPE_DRAGON

        //敵の個数と構造
        ENE_NUM = 14
        ME_TYPE = 0
        ME_TIMER
        ME_DRAG
        ME_VX
        ME_VY
        ME_VZ
        SIZE_OF_ENE

        mEneType1  = v[enePtr1 + ME_TYPE]
        mEneTimer1 = v[enePtr1 + ME_TIMER]
        mEneDrag1  = v[enePtr1 + ME_DRAG]
        mEneVx1    = v[enePtr1 + ME_VX]
        mEneVy1    = v[enePtr1 + ME_VY]
        mEneVz1    = v[enePtr1 + ME_VZ]

        mEneType2  = v[enePtr2 + ME_TYPE]
        mEneTimer2 = v[enePtr2 + ME_TIMER]
        mEneDrag2  = v[enePtr1 + ME_DRAG]
        mEneVx2    = v[enePtr2 + ME_VX]
        mEneVy2    = v[enePtr2 + ME_VY]
        mEneVz2    = v[enePtr2 + ME_VZ]

        //スプライトIDの割り当て
        SPR_ID_BACK    = 0//背景
        SPR_NUM_BACK   = 1
        SPR_ID_ACC     = 1//景観
        SPR_NUM_ACC    = 6
        SPR_ID_GOAL    = 7//終点
        SPR_NUM_GOAL   = 1
        SPR_ID_PLAYER  = 8//自機
        SPR_NUM_PLAYER = 1
        SPR_ID_BULLET  = 9//自弾
        SPR_NUM_BULLET = 1
        SPR_ID_ENEMY   = 10//敵
        SPR_NUM_ENEMY  = ENE_NUM

        //スプライト描画に使う定数
        SPR_BASE_SCALE = 100
        SPR_BASE_ANGLE = 150
        SPR_CENTER_X = 160
        SPR_CENTER_Y = 120
        SPR_MIN_X = (-320)
        SPR_MIN_Y = (-120)
        SPR_MIN_Z = 10
        SPR_MAX_X = (320 + 320)
        SPR_MAX_Y = (120 + 240)
        SPR_MAX_Z = 2000
        SPR_OUT_POS = -320//画面外でピクチャを生成しないとチラつく
        SPR_UNUSED_Z = (SPR_MAX_Z + 1000)

        //スプライトの状態
        SPR_BIT_NONE    = 0
        SPR_BIT_ENABLE  = 1 << 0
        SPR_BIT_SHOW    = 1 << 1
        SPR_BIT_SCALING = 1 << 2
        SPR_BIT_ROTATE  = 1 << 3

        //スプライトの個数と構造
        SPR_NUM = 24
        MS_BIT = 0
        MS_PID
        MS_SCRPTR
        MS_SCALE
        MS_ANGLE
        MS_WX
        MS_WY
        MS_WZ
        SIZE_OF_SPR

        mSpBit1   = v[sprPtr1 + MS_BIT]
        mSpPid1   = v[sprPtr1 + MS_PID]
        mSpScr1   = v[sprPtr1 + MS_SCRPTR]
        mSpScale1 = v[sprPtr1 + MS_SCALE]
        mSpAngle1 = v[sprPtr1 + MS_ANGLE]
        mSpWx1    = v[sprPtr1 + MS_WX]
        mSpWy1    = v[sprPtr1 + MS_WY]
        mSpWz1    = v[sprPtr1 + MS_WZ]

        mSpBit2   = v[sprPtr2 + MS_BIT]
        mSpPid2   = v[sprPtr2 + MS_PID]
        mSpScr2   = v[sprPtr2 + MS_SCRPTR]
        mSpScale2 = v[sprPtr2 + MS_SCALE]
        mSpAngle2 = v[sprPtr2 + MS_ANGLE]
        mSpWx2    = v[sprPtr2 + MS_WX]
        mSpWy2    = v[sprPtr2 + MS_WY]
        mSpWz2    = v[sprPtr2 + MS_WZ]

    }

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

        readyPicCmd = {
            .pos(SPR_OUT_POS, SPR_OUT_POS)
            .topLeft
            .scale(100)
            .trans(100)
            .rgbs(100, 100, 100, 100)
            basePicCmd
        }

        readyTintPicCmd = {
            PATH_TINT
            .pos(160, 120)
            .center
            .scale(100)
            .trans(100)
            .rgbs(100, 100, 100, 100)
            basePicCmd
        }

        framePicCmd = {
            PATH_FRAME
            .pos(0, 0)
            .topLeft
            .scale(100)
            .trans(0)
            .rgbs(100, 100, 100, 100)
            basePicCmd
        }

        lifePicCmd = {
            PATH_LIFE
            .pos(LIFE_X, LIFE_Y)
            .topLeft
            .scale(100)
            .trans(0)
            .grid(1, 5)
            basePicCmd
        }

        readyEnemyPicCmd = {
            PATH_ENEMY
            .center
            .trans(100)
            .rgbs(100, 100, 100, 100)
            .grid(4, 4)
            basePicCmd
        }

        harpyPicCmd = {
            PATH_PLAYER
            .center
            .trans(0)
            .rgbs(100, 100, 100, 100)
            .grid(4, 4)
            basePicCmd
        }

        scorePicCmd = {
            .size(0, 0)
            .trans(0)
            .font("", 12) .bold
            .spacing(0, 4)
            .skin "" .nobg .noframe .noPadding
            basePicCmd
        }
    }

    defv {
        varHead = TV_MINIGAME
        
        ipt
        type
        time
        pid
        cell

        ftA
        ftB
        ftC

        flag//描画に使用する
        enePtr1
        enePtr2
        sprScr1
        sprPtr1
        sprIdx1
        sprPid1
        sprBit1
        sprPtr2
        sprPid2
        sprIdx2
        sprBit2
        lx
        ly
        lz
        rx
        ry
        rz
        scrX
        scrY
        scrScale
        scrAngle
        cosRx
        sinRx
        cosRz
        sinRz

        sceneState//ゲームの状態
        sceneTimer
        triggerFlg//更新フラグ
        stage//ステージ番号
        stageLength//全長
        stageProgress//進行度
        stageVz//スクロール速度
        stageScr//景観のスクロール量
        stageDelay//次のポイントまでの距離
        stageHeight//背景の高さ
        allowAttack//攻撃許可
        score//スコア

        camRx//視点
        camRz
        camX
        camY
        camZ

        playerScrX//主人公
        playerScrY
        playerScale
        playerAngle
        playerVx
        playerVy
        playerAnim
        playerDamage
        playerLife
        playerShootWait

        enemyHead//敵配列の頭
        spriteHead = (__id(enemyHead)  + ENE_NUM * SIZE_OF_ENE)//スプライト配列の頭
        sprZArr    = (__id(spriteHead) + SPR_NUM * (SIZE_OF_SPR))//ソート用の配列
        sprIdArr   = (__id(spriteHead) + SPR_NUM * (SIZE_OF_SPR + 1))

        varFoot = (__id(spriteHead) + SPR_NUM * (SIZE_OF_SPR + 2))//変数の末尾
    }

    deft {
        strQueue = TS_MINIGAME
        strLine
        strDelay
        strType
        strX
        strY
        strZ
    }

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

    //----------------------------
    //敵のポインタを取得する
    __fn _getEnemyPtr $dvDst $i bl {
        v[__id($dvDst)] = __id(enemyHead) + ($i) * SIZE_OF_ENE
    }

    //敵のメンバ変数を一括代入する
    __fn _setEnemyMember $ptr $arr bl {
        v[$ptr..$ptr + SIZE_OF_ENE - 1] = $arr
    }

    //----------------------------
    //スプライトのポインタを取得する
    __fn _getSpritePtr $dvDst $i bl {
        v[__id($dvDst)] = __id(spriteHead) + ($i) * SIZE_OF_SPR
    }

    //スプライトを有効化する
    __fn _activateSprite $ptr bl {
        v[$ptr + MS_BIT] |= SPR_BIT_ENABLE
    }

    //スプライトを無効化する
    __fn _deactivateSprite $ptr bl {
        v[$ptr + MS_BIT] &= (-1) ^ SPR_BIT_ENABLE
    }

    //スプライトの座標を代入する
    __fn _setSpritePosition $ptr $x $y $z bl {
        v[($ptr) + MS_WX..($ptr) + MS_WZ] = [$x, $y, $z]
    }

    //スプライトの状態を設定する
    __fn _setSpriteState $ptr $bit bl {
        v[($ptr) + MS_BIT] = $bit
    }

    //全てのスプライトを初期化する
    __fn _initAllSprite bl {
        //ftA : index
        //ftB : ptr
        //ftC : pid
        @loop SPR_NUM .dst(ftA) bl {
            //ポインタを取得する
            ftB = __id(spriteHead) + ftA * SIZE_OF_SPR
            //変数を初期化
            v[ftB..ftB + SIZE_OF_SPR - 1] = 0
            //ダミーピクチャを指定しておく
            ftC = PIC_SORTED_SPRITES + ftA
            v[ftB + MS_PID] = ftC
            //ダミーピクチャを生成する
            @pic.show [ftC] PATH_DUMMY readyPicCmd
        }
    }

    //スプライトを初期化し、ピクチャを置き換える
    __fn _initSprite $sprId $bit $scr $scale $angle $x $y $z $dvPtr $dvPid $block bl {
        //ポインタを取得する
        v[__id($dvPtr)] = __id(spriteHead) + ($sprId) * SIZE_OF_SPR
        //ピクチャID
        v[__id($dvPid)] = v[$dvPtr + MS_PID]
        //変数を一括初期化
        //ピクチャIDはそのまま
        v[$dvPtr..$dvPtr + SIZE_OF_SPR - 1] = [$bit, $dvPid, $scr, $scale, $angle, $x, $y, $z]
        //ピクチャを初期化する
        $block
    }

    //スプライトごとに処理を行う
    //引数によってIDへの加算やビットフラグの判定の処理が加わる
    __fn _forEachSprite $loop $headerId $checkBit $dvIdx $dvPtr $block bl {
        @loop $loop .dst($dvIdx) bl {
            //ポインタを取得する
            v[__id($dvPtr)] = __id(spriteHead) + ($dvIdx + ($headerId)) * SIZE_OF_SPR

            __if $checkBit bl {
                //ビットフラグで判断する
                @if `!(v[$dvPtr + MS_BIT] & SPR_BIT_ENABLE) bl {
                    @continue
                }
                $block
            } .else bl {
                $block
            }
        }
    }

    //使われていない敵スプライトを探し、そのポインタを返す
    //見つからない場合は0を返す
    __fn _findUnusedEnemyPtr $dvSprPtr $dvEnePtr bl {
        v[__id($dvSprPtr)] = 0
        v[__id($dvEnePtr)] = 0
        //ftA : index
        //ftB : ptr
        @loop SPR_NUM_ENEMY .dst(ftA) bl {
            _getSpritePtr(ftB, ftA + SPR_ID_ENEMY)
            //ビットフラグで判断する
            @if `!(v[ftB + MS_BIT] & SPR_BIT_ENABLE) bl {
                v[__id($dvSprPtr)] = ftB
                _getEnemyPtr($dvEnePtr, ftA)
                @break
            }
        }
    }

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

    //自機のアニメーションを変える
    __fn _changePlayerAnime $state bl {
        triggerFlg |= TR_BIT_PLAYER_ANIM
        playerAnim = $state
    }

    //スコアを増やす
    __fn _addScore $p bl {
        score += $p
        bitOn(triggerFlg, TR_BIT_SCORE)
    }

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

    //暗転
    __fn _setTint $trans $time bl {
        @pic.move[PIC_TINT] .pos(160, 120) .center .scale2(1600, 1300) .trans($trans) .time($time)
    }

    //------------------------------------------------------------------------------------
    //開始処理
    bl {
        //変数を初期化
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, TS_MINIGAME, NUM_OF_STR)
        //BGMを記憶する
        storeAndStopBGM()
        //メッセージの表示位置
        msgBottom()
        //ピクチャ
        @pic.show [PIC_FRAME] framePicCmd
        @pic.show [PIC_TINT] readyTintPicCmd
        @pic.show [PIC_DIST] PATH_DIST readyPicCmd
        @pic.show [PIC_CURSOR] PATH_CURSOR readyPicCmd
        //全てのスプライトを初期化
        _initAllSprite()
        //暗転
        fastFadeInTintOnly(1)
        @label.jump "gameLoop"
    }

    //------------------------------------------------------------------------------------
    //ゲーム処理
    @label.set "gameLoop"
    bl {
        //ステージとスコアを初期化
        stage = 0
        score = 0

        //----------------------------
        //ステージ開始時
        @label.set "nextStage"

        //暗転
        _setTint(0, 0)
        @wait(0)

        //BGM
        startBGM("energy", FALSE, 0, 100, 100, 50)

        //状態
        _changeSceneState(SCENE_STATE_OPENING)

        //----------------------------
        //ステージ
        stageLength = STAGE_LENGTH
        stageProgress = 0
        stageVz = 0
        stageScr = 0
        stageDelay = 0
        stageHeight = [400, 350, 700][stage]
        allowAttack = FALSE

        //配置
        @if stage == 0 bl {
            strQueue .asg(STR_STAGE1)
        } .elif stage == 1 bl {
            strQueue .asg(STR_STAGE2)
        } .elif stage == 2 bl {
            strQueue .asg(STR_STAGE3)
        } .else bl {
            strQueue .asg("")
        }

        //----------------------------
        //ビットフラグ
        triggerFlg = TR_BIT_SCORE | TR_BIT_HISCORE | TR_BIT_LIFE | TR_BIT_DIST
        //カメラ
        V3_set(camX, 0, CAMERA_BASE_Y, 0)
        camRx = 0
        camRz = 0
        //プレイヤー
        V2_set(playerVx, 0, 0)
        playerAnim = PLAYER_ANIM_NEUTRAL
        playerDamage = 0
        playerLife = PLAYER_LIFE
        playerShootWait = 0

        //----------------------------
        //ピクチャを準備する
        cell = stage + 1
        @pic.show [PIC_ENDING] PATH_ENDING .cell(cell) .grid(1, 3) readyPicCmd
        @pic.show [PIC_OP_HARPY] .cell(1) harpyPicCmd
        @pic.show [PIC_OP_WALL] PATH_WALL readyPicCmd
        @pic.move [PIC_DIST] .pos(DIST_X, DIST_Y) .topLeft 

        //----------------------------
        //スプライトを初期化する
        //背景
        _initSprite(SPR_ID_BACK, SPR_BIT_ENABLE | SPR_BIT_ROTATE, 0, 100, 0, 0, BACK_Y, BACK_Z, 
            sprPtr1, pid,
            bl {
                cell = stage + 1
                @pic.show [pid] PATH_BACK .cell(cell) .grid(1, 3) readyPicCmd
            }
        )

        //ゴール
        _initSprite(SPR_ID_GOAL, SPR_BIT_ROTATE | SPR_BIT_SCALING, 0, GOAL_SCALE, 0, 0, GOAL_Y, SPR_MAX_Z + 1, 
            sprPtr1, pid,
            bl {
                cell = stage + 1
                @pic.show [pid] PATH_GOAL .cell(cell) .grid(1, 3) readyPicCmd
            }
        )

        //主人公
        //画面下に設置する
        //有効化しておかないと一瞬だけ見えてしまう
        _initSprite(SPR_ID_PLAYER, SPR_BIT_ENABLE | SPR_BIT_ROTATE | SPR_BIT_SCALING, __id(playerScrX), 100, 0, 0, 100, PLAYER_POS_Z,
            sprPtr1, pid,
            bl {
                @pic.show [pid] .cell(1) harpyPicCmd
            }
        )

        //自弾
        _initSprite(SPR_ID_BULLET, SPR_BIT_ROTATE | SPR_BIT_SCALING, 0, 100, 0, 0, 0, 0,
            sprPtr1, pid,
            bl {
                @pic.show [pid] PATH_BULLET readyPicCmd
            }
        )

        //景観
        @loop SPR_NUM_ACC .dst(sprIdx1) bl {
            sprIdx1 += SPR_ID_ACC

            _initSprite(sprIdx1, SPR_BIT_ENABLE | SPR_BIT_ROTATE | SPR_BIT_SCALING, 0, GROUND_SCALE, 0, 0, 0, 0,
                sprPtr1, pid,
                bl {
                    cell = stage + 1
                    @pic.show [pid] PATH_GROUND .cell(cell) .grid(1, 3) readyPicCmd
                }
            )
        }

        //敵
        @loop SPR_NUM_ENEMY .dst(sprIdx1) bl {
            //敵メンバ変数を初期化する
            _getEnemyPtr(enePtr1, sprIdx1)
            _setEnemyMember(enePtr1, [0, 0, 0, 0, 0, 0] )
            //敵スプライト変数を初期化する
            sprIdx1 += SPR_ID_ENEMY
            _initSprite(sprIdx1, SPR_BIT_ROTATE | SPR_BIT_SCALING, 0, 100, 0, 0, 0, 0,
                sprPtr1, pid,
                bl {
                    @pic.show [pid] .cell(1) readyEnemyPicCmd
                }
            )
        }

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

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

            //----------------------------
            //シーン制御用タイマー
            sceneTimer += 1

            //----------------------------
            //ゲーム中
            @if sceneState == SCENE_STATE_GAME bl {
                //何もしない
            //----------------------------
            //撃墜
            } .elif sceneState == SCENE_STATE_DOWN bl {
                $eventFrame3 = 90
                //最初のフレーム
                @if sceneTimer == 0 bl {
                    V2_set(playerVx, 0, -8)
                    @se.play "Fall1" .opt(100, 80, 50)
                }

                //自機
                _getSpritePtr(sprPtr1, SPR_ID_PLAYER)
                //回転して揺れながら落下する
                playerVy += (sceneTimer % 3 == 0) ? 1 : 0
                mSpAngle1 = (mSpAngle1 + 10 * UNIT_ANGLE + UNIT_LOOP) % UNIT_LOOP
                mSpWy1 += playerVy
                mSpWz1 -= 1

                //ゲームオーバー
                @if sceneTimer >= $eventFrame3 bl {
                    _changeSceneState(SCENE_STATE_GAMEOVER)
                }

            //----------------------------
            //オープニング
            } .elif sceneState == SCENE_STATE_OPENING bl {
                $animNum = 6
                $animFrame = 12
                $eventFrame1 = 64
                $eventFrame2 = 64
                $eventFrame3 = 150

                //最初のフレーム
                @if sceneTimer == 0 bl {
                    //get ready
                    cell = stage + 1
                    @pic.strpic[PIC_EVENT] __str("     \c[2]STAGE \", cell, "\c[0]", NEWLINE, "PRESS ANY BUTTON") .pos(160, 240) .scale(100) .top scorePicCmd
                    @pic.move[PIC_EVENT] .relative .pos(0, -148) .scale(0) .trans(0) .time(5)
                    //壁
                    @pic.move[PIC_OP_WALL] .pos(32, 128) .topLeft .scale(100) .trans(0)
                    //カメラの角度を上向きに
                    camRx = -20 * UNIT_ANGLE
                    camY = CAMERA_BASE_Y
                    //暗転解除
                    _setTint(100, 2)
                }

                //出撃前のアニメーション
                @if `between(sceneTimer, 0, $animFrame * ($animNum - 1)) bl {
                    @if `sceneTimer % $animFrame == 0 bl {
                        time = sceneTimer / $animFrame

                        lx = [110, 120, 130, 140, 150 ,160][time]//6
                        ly = [150, 150, 150, 150, 150, 150][time]
                        cell = [1, 2, 1, 2, 1, 3][time]
                        @pic.show[PIC_OP_HARPY] .pos(lx, ly) .cell(cell) harpyPicCmd
                    }
                }

                //入力されるまでカウントが増えなくなる
                @if sceneTimer == $eventFrame1 - 1 bl {
                    getAnyKey(ipt, FALSE)
                    @if `!ipt bl {
                        sceneTimer -= 1
                    }
                }

                //出撃する
                @if `between(sceneTimer, $eventFrame1, $eventFrame3) bl {
                    @if sceneTimer == $eventFrame1 bl {
                        hidePicture(PIC_EVENT)
                        //前景移動
                        @pic.move[PIC_OP_WALL] .relative .pos(0, 120) .scale(20) .trans(0) .time(4)
                        @pic.move[PIC_OP_HARPY] .relative .pos(0, 120) .scale(20) .trans(0) .time(4)
                    }
                    //カメラを下げる
                    camRx = min(camRx + 4, CAMERA_BASE_RX)
                    //スクロール速度
                    stageVz = min(stageVz + 1, SCROLL_BASE_VZ)
                }

                //自機を設置する
                @if `between(sceneTimer, $eventFrame2, $eventFrame3) bl {
                    _getSpritePtr(sprPtr1, SPR_ID_PLAYER)

                    @if sceneTimer == $eventFrame2 bl {
                        _changePlayerAnime(PLAYER_ANIM_NEUTRAL)
                        @se.play "Wind10" .opt(100, 50, 50)

                    }

                    //下から現れる
                    _activateSprite(sprPtr1)
                    mSpWy1 = max(mSpWy1 - 2, 0)
                }

                //シーン変更
                @if sceneTimer > $eventFrame3 bl {
                    //ピクチャを隠す
                    hidePicturesForEach( [PIC_EVENT, PIC_OP_WALL, PIC_OP_HARPY] )
                    _changeSceneState(SCENE_STATE_GAME)
                }

            //----------------------------
            //ゴールイン
            } .elif sceneState == SCENE_STATE_GOAL bl {
                $eventFrame1 = 60
                $eventFrame2 = 80
                $eventFrame3 = 100
                $eventFrame4 = 150
                $eventFrame5 = 160

                @if `between(sceneTimer, 0, $eventFrame4) bl {
                    //----------------------------
                    //ゴール
                    _getSpritePtr(sprPtr1, SPR_ID_GOAL)

                    @if `sceneTimer == 0 bl {
                        //位置は初期化時に設定されている
                        mSpBit1 |= SPR_BIT_ENABLE
                    } .else bl {
                        //画面奥から移動する
                        mSpWz1 -= stageVz
                    }

                    //----------------------------
                    //自機とカメラ
                    //lx,ly,lz
                    _getSpritePtr(sprPtr1, SPR_ID_PLAYER)

                    //最初のフレーム
                    @if `sceneTimer == 0 bl {
                        //アニメーション
                        _changePlayerAnime(PLAYER_ANIM_UP)
                        //スクロール速度を設定
                        stageVz = 21
                        @se.play "Holy5" .opt(100, 100, 50)
                    }

                    //スクロールを止める
                    @if `sceneTimer == $eventFrame1 bl {
                        stageVz = 0
                    }

                    //自機を非表示にする
                    @if sceneTimer == $eventFrame4 bl {
                        _deactivateSprite(sprPtr1)
                    }
                    
                    //準備
                    @if `sceneTimer < $eventFrame2 bl {
                        //カメラの向きを戻す
                        camRx -= clamp(camRx, -5, 5)
                        camRz -= clamp(camRz, -5, 5)
                        //自機を画面端に移動させる
                        V3_set(lx, PLAYER_POS_MAX / 2, -PLAYER_POS_MAX, 0)

                    //突撃
                    } .else bl {
                        @if `sceneTimer == $eventFrame2 bl {
                            //アニメーション
                            _changePlayerAnime(PLAYER_ANIM_DOWN)
                            @se.play "Wind1" .opt(100, 80, 50)
                        }
                        //自機を移動させる
                        V3_set(lx, 0, 0, 2)
                    }
                    
                    //自機の移動
                    lx -= mSpWx1
                    ly -= mSpWy1
                    updateSpeedToApproach(playerVx, lx, playerVx, PLAYER_ACC_LIMIT)
                    updateSpeedToApproach(playerVy, ly, playerVy, PLAYER_ACC_LIMIT)
                    mSpWx1 += playerVx / 3
                    mSpWy1 += playerVy / 3
                    mSpWz1 += lz
                    mSpAngle1 = clamp(mSpAngle1, -5, 5)
                }

                //一枚絵を表示する
                @if sceneTimer == $eventFrame4 bl {
                    @se.play "Ice6" .opt(100, 100, 50)
                    //stage clear
                    @pic.strpic[PIC_EVENT] "\c[2]STAGE CLEAR!!\" .pos(360, 185) .scale(200) .center scorePicCmd
                    @pic.move[PIC_ENDING] .pos(360, 120) .center .scale(100) .rgbs(200, 200, 200, 100)
                    //一瞬だけ止まる
                    @wait(0)

                    $time = 2
                    @pic.move[PIC_EVENT] .pos(160, 185) .center .scale(200) .time($time)
                    @pic.move[PIC_ENDING] .pos(160, 120) .center .scale(100) .rgbs(100, 100, 100, 100) .time($time)

                    _setTint(50, $time)

                    //実績
                    checkSetAchievement(achievedHarpy, score >= HT_ACHIEVE_COUNT)
                }

                //次のシーンへ
                @if sceneTimer >= $eventFrame5 bl {
                    //キーが入力されるまで
                    getAnyKey(ipt, FALSE)
                    @if `ipt bl {
                        //ピクチャを隠す
                        hidePicturesForEach( [PIC_EVENT, PIC_ENDING] )
                        //ゲームオーバー
                        @if stage >= STAGE_MAX bl {
                            _changeSceneState(SCENE_STATE_GAMEOVER)
                        //次のステージへ
                        } .else bl {
                            stage = clamp(stage + 1, 0, STAGE_MAX)
                            @label.jump "nextStage"
                        }
                    }
                }

            //----------------------------
            //ゲームオーバー
            } .elif sceneState == SCENE_STATE_GAMEOVER bl {
                $eventFrame1 = 80
                //最初のフレーム
                @if sceneTimer == 0 bl {
                    //スコア更新
                    _updateHighScore()
                    //暗転
                    _setTint(50, 2)
                    //bgmを止める
                    stopBGM(1000)
                    //ハイスコア
                    @pic.strpic[PIC_EVENT] __str("\c[2]GAME OVER\c[0]") .pos(160, 240) .scale(100) .top scorePicCmd
                    @pic.move[PIC_EVENT] .relative .pos(0, -148) .scale(0) .trans(0) .time(5)
                }

                //選択肢
                @if sceneTimer >= $eventFrame1 bl {
                    replayProcess("gameLoop", "gameEnd")
                }
            }

             //----------------------------
            //ステージ進行
            @if sceneState == SCENE_STATE_GAME bl {
                //一定距離進むごとにスコアが入り、表示が更新される
                //スコアの量はY座標によって決まる
                @if `stageProgress / STAGE_INTERVAL != (stageProgress + stageVz) / STAGE_INTERVAL bl {
                    _getSpritePtr(sprPtr1, SPR_ID_PLAYER)
                    cell = SCORE_RUN + SCORE_SPEED * mSpWy1 / PLAYER_POS_MAX

                    _addScore(cell)
                    bitOn(triggerFlg, TR_BIT_DIST)
                }

                //進行
                stageProgress += stageVz
                stageDelay -= stageVz

                //ゴール判定
                @if stageProgress >= stageLength bl {
                    _changeSceneState(SCENE_STATE_GOAL)
                    //敵を全て消す
                    _forEachSprite(SPR_NUM_ENEMY, SPR_ID_ENEMY, FALSE,
                        sprIdx1, sprPtr1,
                        bl {
                            _deactivateSprite(sprPtr1)
                        }
                    )

                } .else bl {
                    //ステージの読み込み
                    @while stageDelay <= 0 bl {
                        //読み込む文字列がない
                        strQueue .getLen(time)
                        @if time <= 0 bl {
                            @break
                        }

                        //一行切り出し
                        strQueue .popLine(strLine)
                        strLine .split(",", strDelay, time)

                        //分割数が足りない、あるいは多すぎる場合は読み飛ばす
                        @if `!between(time, 2, 5) bl {
                            @continue
                        }

                        //待ち時間増加(*100)
                        strDelay .toNum(time)
                        stageDelay += time * 100

                        //----------------------------
                        //敵を追加する

                        //種類
                        strType .toNum(type)
                        @if `between(type, ENEMY_TYPE_EXPLOSION, ENEMY_TYPE_DRAGON) bl {
                            //座標(*10)
                            strX .toNum(lx)
                            strY .toNum(ly)
                            strZ .toNum(lz)
                            V3_asMulScalar(lx, 10)
                            //空きを探す
                            _findUnusedEnemyPtr(sprPtr1, enePtr1)
                            //空きが見つかった
                            @if sprPtr1 > 0 bl {
                                //敵変数を初期化する
                                _setEnemyMember(enePtr1, [type, 0, 0, 0, 0, 0] )
                                //スプライト変数
                                _setSpritePosition(sprPtr1, lx, ly, lz)
                                mSpScale1 = 100
                                mSpAngle1 = 0
                                mSpScr1 = 0
                                //スプライトを起動する
                                _activateSprite(sprPtr1)
                                //ピクチャの初期化は反復処理中に行う
                            }
                        }
                    }
                }
            }

            //----------------------------
            //自弾
            _getSpritePtr(sprPtr1, SPR_ID_BULLET)
            @if `mSpBit1 & SPR_BIT_ENABLE bl {
                //拡大率
                scrScale = 90 + PLAYER_SHOOT_SCA * mSpWz1 / SPR_MAX_Z
                //回転する
                mSpAngle1 = (mSpAngle1 + 20 * UNIT_ANGLE + UNIT_LOOP) % UNIT_LOOP
                mSpScale1 = 100
                //速度は一定
                mSpWz1 += PLAYER_SHOOT_VZ
                //衝突判定用の半径
                scrScale = PLAYER_SHOOT_RAD * scrScale / 100
                //衝突フラグ
                flag = FALSE
                //敵との衝突判定
                @if `allowAttack bl {
                    _forEachSprite(SPR_NUM_ENEMY, SPR_ID_ENEMY, TRUE,
                        sprIdx2, sprPtr2,
                        bl {
                            //敵変数へのポインタを取得
                            _getEnemyPtr(enePtr2, sprIdx2)

                            //弾や爆発は無視する
                            type = mEneType2
                            @if `type == ENEMY_TYPE_BULLET || type == ENEMY_TYPE_EXPLOSION bl {
                                @continue
                            }

                            //衝突判定
                            @if `abs(mSpWx1 - mSpWx2) < scrScale &&
                                abs(mSpWy1 - mSpWy2) < scrScale &&
                                abs(mSpWz1 - mSpWz2) < scrScale bl {
                                //自弾の衝突フラグ
                                flag = TRUE
                                //敵タイプを爆発に変更する
                                _setEnemyMember(enePtr2, [ENEMY_TYPE_EXPLOSION, 0, 0, 0, 0, 0] )
                                //スコア
                                _addScore(SCORE_ENEMY)
                            }
                        }
                    )
                }

                //画面奥に到達するか、敵と衝突すると消える
                @if `mSpWz1 >= SPR_MAX_Z || flag bl {
                    _deactivateSprite(sprPtr1)
                }
            }

            //----------------------------
            //自機
            @if sceneState == SCENE_STATE_GAME bl {
                _getSpritePtr(sprPtr1, SPR_ID_PLAYER)

                //デバッグ
                //@key.input .dst(ipt) .shift
                //@if `ipt && playerDamage <= 0 bl {
                //    bitOn(triggerFlg, TR_BIT_PLAYER_DAMAGE)
                //}

                //方向ボタン
                V2_getInput(rx)
                //上下反転
                @if gameMode == PLAYER_CTRL_REVERSE bl {
                    ry *= -1
                }

                //目標位置
                V2_set(lx,
                    rx ? (rx * PLAYER_POS_MAX - mSpWx1) : 0,
                    ry ? (ry * PLAYER_POS_MAX - mSpWy1) : 0
                )
                //速度
                updateSpeedToApproach(playerVx, lx, playerVx, PLAYER_ACC_LIMIT)
                updateSpeedToApproach(playerVy, ly, playerVy, PLAYER_ACC_LIMIT)
                //位置を更新する
                mSpWx1 += playerVx / 3//割と適当な制御
                mSpWy1 += playerVy / 3
                mSpWz1 = PLAYER_POS_Z
                //回転
                mSpAngle1 = mSpWx1 * (-20 * UNIT_ANGLE) / PLAYER_POS_MAX + playerVx * (2 * UNIT_ANGLE)
                //アニメーションを更新する
                $threshold = 10
                type = playerAnim
                //ダメージ
                @if playerDamage > 0 bl {
                    type = PLAYER_ANIM_DAMAGE
                //下降
                } .elif `playerVy > $threshold bl {
                    type = PLAYER_ANIM_DOWN
                //上昇
                } .elif `playerVy < -$threshold bl {
                    type = PLAYER_ANIM_UP
                //横
                } .elif `abs(playerVx) > $threshold bl {
                    type = PLAYER_ANIM_SLIDE
                //停止
                } .elif `playerVx == 0 && playerVy == 0 {
                    type = PLAYER_ANIM_NEUTRAL
                }

                @if type != playerAnim bl {
                    _changePlayerAnime(type)
                }

                //----------------------------
                //カメラの角度
                //10度ほど下に向いている
                camRx = mSpWy1 * (10 * UNIT_ANGLE) / PLAYER_POS_MAX + CAMERA_BASE_RX
                camRz = mSpWx1 * (20 * UNIT_ANGLE) / PLAYER_POS_MAX
                //スクロール速度
                stageVz = SCROLL_BASE_VZ + mSpWy1 * SCROLL_ADD_VZ / PLAYER_POS_MAX

                //----------------------------
                //射撃
                @key.input .dst(ipt) .decision
                @if playerShootWait > 0 bl {
                    playerShootWait -= 1

                } .elif `ipt && allowAttack bl {
                    playerShootWait = PLAYER_SHOOT_WAIT
                    //弾丸を配置する
                    _getSpritePtr(sprPtr2, SPR_ID_BULLET)
                    mSpBit2 |= SPR_BIT_ENABLE
                    mSpAngle2 = 0
                    mSpScale2 = 100
                    _setSpritePosition(sprPtr2, mSpWx1, mSpWy1, mSpWz1 + 1)

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

                //----------------------------
                //被弾
                @if `triggerFlg & TR_BIT_PLAYER_DAMAGE bl {
                    bitOff(triggerFlg, TR_BIT_PLAYER_DAMAGE)
                    //被弾モーション
                    _changePlayerAnime(PLAYER_ANIM_DAMAGE)
                    playerDamage = PLAYER_DAMAGE
                    //ライフ減少
                    //無敵モード中は減らない
                    @if invincibleSwitch.isOff bl {
                        playerLife = max(playerLife - 1, 0)
                        bitOn(triggerFlg, TR_BIT_LIFE)
                    }
                    //被弾音
                    @se.play "Damage1" .opt(100, 100, 50)

                    //撃墜判定
                    @if playerLife <= 0 bl {
                        _changeSceneState(SCENE_STATE_DOWN)
                    //ピンチ判定
                    } .elif playerLife == 1 bl {
                        @se.play "alert1" .opt(50, 130, 50)
                    }

                //自機の被弾モーションカウンタ
                } .elif playerDamage > 0 bl {
                    playerDamage -= 1
                }
            }

            //----------------------------
            //自機のアニメーションを更新する
            @if `triggerFlg & TR_BIT_PLAYER_ANIM bl {
                bitOff(triggerFlg, TR_BIT_PLAYER_ANIM)

                __fn _if_setPlayerAnimPattern $id $arr bl {
                    @if playerAnim == $id bl {
                        v[__id(lx)..__id(lx) + 1] = $arr
                    }
                }

                _if_setPlayerAnimPattern( PLAYER_ANIM_NEUTRAL, [5, 7] )
                _if_setPlayerAnimPattern( PLAYER_ANIM_SLIDE, [9, 10] )
                _if_setPlayerAnimPattern( PLAYER_ANIM_DOWN, [11, 12] )
                _if_setPlayerAnimPattern( PLAYER_ANIM_UP, [13, 14] )
                _if_setPlayerAnimPattern( PLAYER_ANIM_DAMAGE, [15, 16] )

                //ピクチャを置き換える
                //showで生成しmoveで移動させるとチラつきが生じる為、同じ場所に設置しなおす必要がある
                _getSpritePtr(sprPtr1, SPR_ID_PLAYER)

                pid = mSpPid1
                @pic.show [pid] .pos(playerScrX, playerScrY) .scale(playerScale) .angle(playerAngle, UNIT_ANGLE) .rangeAnim(8, lx, ly) harpyPicCmd
            }

            //----------------------------
            //敵を更新する
            _forEachSprite(SPR_NUM_ENEMY, SPR_ID_ENEMY, TRUE,
                sprIdx1, sprPtr1,
                bl {
                    //敵変数へのポインタを取得
                    _getEnemyPtr(enePtr1, sprIdx1)
                    //----------------------------
                    //タイプによって分岐する
                    type = mEneType1
                    //タイマー
                    time = mEneTimer1
                    //射撃スイッチ
                    flag = FALSE
                    //----------------------------
                    //爆発
                    @if type == ENEMY_TYPE_EXPLOSION bl {
                        $interval = 6

                        @if time == 0 bl {
                            mEneDrag1  = 2
                            mSpAngle1 = 0
                            mSpScale1 = 150

                            pid = mSpPid1
                            @pic.show[pid] .rangeAnim($interval, 1, 4) readyEnemyPicCmd

                            //効果音
                            @se.play "bom0" .opt(80, 80, 50)
                        }

                        //爆発アニメーションが終わると消える
                        @if `mEneTimer1 >= $interval * 4 bl {
                            _deactivateSprite(sprPtr1)
                            @continue
                        }
                    //----------------------------
                    //弾丸
                    //回転しながら飛ぶ
                    } .elif type == ENEMY_TYPE_BULLET bl {
                        //初期化は発射時に行う
                        mSpAngle1 = (mSpAngle1 - 10 * UNIT_ANGLE + UNIT_LOOP) % UNIT_LOOP

                        @if `allowAttack bl {
                            _getSpritePtr(sprPtr2, SPR_ID_PLAYER)

                            //衝突判定
                            @if `abs(mSpWx1 - mSpWx2) < PLAYER_RAD &&
                                abs(mSpWy1 - mSpWy2) < PLAYER_RAD &&
                                abs(mSpWz1 - mSpWz2) < PLAYER_RAD bl {
                                //被弾
                                bitOn(triggerFlg, TR_BIT_PLAYER_DAMAGE)
                                //弾は消える
                                _deactivateSprite(sprPtr1)
                                @continue
                            }
                        }
                    //----------------------------
                    //コウモリ
                    //背後から回り込むように現れ、一発撃つ
                    } .elif type == ENEMY_TYPE_BAT bl {
                        @if time == 0 bl {
                            mEneDrag1 = 3
                            mEneVx1 = (mSpWx1 > 0) ? -2 : 2
                            mEneVz1 = 28

                            mSpScale1 = 100
                            mSpAngle1 = 0

                            pid = mSpPid1
                            @pic.show[pid] .rangeAnim(8, 7, 8) readyEnemyPicCmd

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

                        @if `time == 80 bl {
                            flag = TRUE
                        }

                        @if `!(time % 4) bl {
                            mEneVz1 -= 1
                        }

                    //----------------------------
                    //鬼火
                    //前方から螺旋を描きながら現れ、一発撃つ
                    } .elif type == ENEMY_TYPE_GHOST bl {
                        //初期角度は初期位置で決まる
                        @if time == 0 bl {
                            mEneDrag1 = 3
                            mEneVz1 = -5

                            mSpScale1 = 100
                            mSpAngle1 = atan2(mSpWy1, mSpWx1, UNIT_ANGLE) - 90 * UNIT_ANGLE

                            pid = mSpPid1
                            @pic.show[pid] .rangeAnim(8, 9, 10) readyEnemyPicCmd

                            @se.play "Fog1" .opt(70, 140, 50)
                        }

                        @if `mSpWz1 > 500 bl {
                            @if `time == 80 bl {
                                flag = TRUE
                            }
                            scrAngle = mSpAngle1 + 90 * UNIT_ANGLE
                            mEneVx1 = cos(scrAngle, UNIT_ANGLE, 70) - mSpWx1
                            mEneVy1 = sin(scrAngle, UNIT_ANGLE, 70) - mSpWy1
                            mSpAngle1 = (mSpAngle1 + 4 * UNIT_ANGLE) % UNIT_LOOP
                        }

                    //----------------------------
                    //マーマン
                    //地面から現れ、一発発射して落ちる
                    } .elif type == ENEMY_TYPE_MERMAN bl {
                        @if time == 0 bl {
                            mEneDrag1 = 3
                            mEneVy1 = -14
                            mEneVz1 = 12

                            mSpScale1 = 120
                            mSpAngle1 = 0

                            pid = mSpPid1
                            @pic.show[pid] .rangeAnim(8, 11, 12) readyEnemyPicCmd

                            @se.play "Water1" .opt(70, 120, 50)

                        }

                        @if `time == 60 bl {
                            flag = TRUE
                        }

                        @if `!(time % 4) bl {
                            mEneVy1 += 1
                        }

                    //----------------------------
                    //グリフォン
                    //一定距離まで近づくと停止し、弾を三発撃って横に逃げる
                    } .elif type == ENEMY_TYPE_GRIFFON bl {
                        @if time == 0 bl {
                            mEneDrag1 = 4
                            mEneVz1 = -35

                            mSpScale1 = 150
                            mSpAngle1 = 0

                            pid = mSpPid1
                            @pic.show[pid] .rangeAnim(8, 13, 14) readyEnemyPicCmd

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

                        @if time == 30 bl {
                            mEneVz1 = 5
                        }

                        @if `time == 70 || time == 78 || time == 86 bl {
                            flag = TRUE
                        }

                        @if time >= 100 bl {
                            mEneVx1 += (mSpWx1 > 0) ? 1 : -1
                            mEneVz1 = 0
                            mSpAngle1 = mEneVx1 * 2 * UNIT_ANGLE
                        }

                    //----------------------------
                    //ドラゴン
                    //往復しながら連射する
                    } .elif type == ENEMY_TYPE_DRAGON bl {
                        @if time == 0 bl {
                            mEneDrag1 = 4
                            mEneVz1 = -2

                            mSpScale1 = 150
                            mSpAngle1 = 0

                            pid = mSpPid1
                            @pic.show[pid] .rangeAnim(8, 15, 16) readyEnemyPicCmd

                            @se.play "Monster2" .opt(50, 140, 50)
                        }

                        @if `mSpWz1 > 500 bl {
                            @if `!(time % 2) bl {
                                mEneVx1 -= mSpWx1 > 0 ? 1 : -1
                                mEneVy1 -= mSpWy1 > 0 ? 1 : -1
                                mSpAngle1 = mEneVx1 * 2 * UNIT_ANGLE
                            }

                            @if `time > 60 && !(time % 12)  bl {
                                flag = TRUE
                            }
                        }
                    }

                    //----------------------------
                    //共通処理
                    //射撃
                    @if `flag && allowAttack bl {
                        //xy速度は自機狙い固定
                        _getSpritePtr(sprPtr2, SPR_ID_PLAYER)

                        //着弾時間
                        //ゼロ除算を回避
                        scrScale = ENEMY_SHOOT_VZ - stageVz
                        scrScale = scrScale ? scrScale : 1
                        scrScale = (mSpWz2 - mSpWz1) / scrScale
                        scrScale = scrScale ? scrScale : 1

                        //弾の速度
                        V3_set(lx,
                            (mSpWx2 - mSpWx1) / scrScale,
                            (mSpWy2 - mSpWy1) / scrScale,
                            ENEMY_SHOOT_VZ
                        )

                        //_forEachSprite内ではglobal系列の変数は使っていない
                        _findUnusedEnemyPtr(sprPtr2, enePtr2)
                        @if sprPtr2 > 0 bl {
                            //スプライトを起動する
                            _activateSprite(sprPtr2)
                            //敵変数を初期化する
                            _setEnemyMember(enePtr2, [ENEMY_TYPE_BULLET, 0, 1, lx, ly, lz] )
                            //スプライト変数
                            mSpScale2 = 100
                            mSpAngle2 = 0
                            _setSpritePosition(sprPtr2, mSpWx1, mSpWy1, mSpWz1 - 5)//少し前から出る
                            //ピクチャを置き換える
                            pid = mSpPid2
                            @pic.show[pid] .rangeAnim(4, 5, 6) readyEnemyPicCmd
                            //効果音
                            @se.play "Ice2" .opt(80, 150, 50)
                        }
                    }

                    //カウンタ
                    mEneTimer1 += 1

                    //移動
                    mSpWx1 += mEneVx1
                    mSpWy1 += mEneVy1
                    mSpWz1 += mEneVz1

                    //スクロールに流される
                    @if `mEneDrag1 bl {
                        mSpWz1 -= stageVz / mEneDrag1
                    }

                    //画面端に到達するか一定時間経つとタイプ問わずに消える
                    @if `time >= ENEMY_MAX_TIME ||
                         !between( mSpWz1, 0, SPR_MAX_Z + 100 ) ||
                         !between( mSpWx1, -ENEMY_MAX_POS, ENEMY_MAX_POS ) ||
                         !between( mSpWy1, -ENEMY_MAX_POS, stageHeight ) bl {
                        _deactivateSprite(sprPtr1)
                        @continue
                    }
                }
            )

            //----------------------------
            //景観を更新する
            @if stageVz != 0 bl {
                stageScr = (stageScr - stageVz + SPR_MAX_Z) + SPR_MAX_Z
                //x:スプライトIDによってずれる
                //y:下からにょきっと生える
                //z:等間隔に配置される
                _forEachSprite(SPR_NUM_ACC, SPR_ID_ACC, TRUE,
                    sprIdx1, sprPtr1,
                    bl {
                        lz = (SPR_MAX_Z * sprIdx1 / SPR_NUM_ACC + stageScr) % SPR_MAX_Z
                        mSpWx1 = ((sprIdx1 & 0x01) ? 1 : -1) * 72
                        mSpWy1 = clamp(lz - SPR_MAX_Z + 100, 0, 100) + stageHeight
                        mSpWz1 = lz + SPR_MIN_Z

                    }
                )
            }

            //----------------------------
            //攻撃の許可
            allowAttack = (playerDamage <= 0 && sceneState == SCENE_STATE_GAME) ? TRUE : FALSE

            //----------------------------
            //更新フラグ
            @if `triggerFlg bl {
                //----------------------------
                //スコアを表示する
                @if `triggerFlg & TR_BIT_SCORE bl {
                    bitOff(triggerFlg, TR_BIT_SCORE)
                    @pic.strpic [PIC_SCORE] __str("\c[5]SCORE \c[4]\", score) .pos(SCORE_X, SCORE_Y) .topLeft .scale(100) scorePicCmd
                }

                //----------------------------
                //ハイスコアを表示する
                @if `triggerFlg & TR_BIT_HISCORE bl {
                    bitOff(triggerFlg, TR_BIT_HISCORE)
                    @pic.strpic [PIC_HISCORE] __str("\c[5]TOP \c[4]\", hatansStoryScore) .pos(HISCORE_X, HISCORE_Y) .topLeft .scale(100) scorePicCmd
                }

                //----------------------------
                //距離を表示する
                @if `triggerFlg & TR_BIT_DIST bl {
                    bitOff(triggerFlg, TR_BIT_DIST)

                    V2_set(lx, DIST_X + 15 + 78 * stageProgress / stageLength , DIST_Y)
                    @pic.move [PIC_CURSOR] .pos(lx, ly) .center
                }

                //----------------------------
                //ライフを表示する
                @if `triggerFlg & TR_BIT_LIFE bl {
                    bitOff(triggerFlg, TR_BIT_LIFE)

                    cell = playerLife + 1
                    @pic.show [PIC_LIFE] .cell(cell) .rgbs(200, 200, 200, 100) lifePicCmd
                    @pic.move [PIC_LIFE] .relative .pos(0, 0) .scale(0) .trans(0) .rgbs(100, 100, 100, 100) .time(4) 
                }
            }

            //----------------------------
            //Z座標でソートする
            //負荷が半分になったりしないかな！
            @if `sceneTimer % 2 == 0 bl {
                //Z座標とスプライト番号を列挙し、ピクチャを一時退避させる
                //未使用のスプライトは最奥にあるものとして扱う
                @loop SPR_NUM .dst(sprIdx1) bl {
                    _getSpritePtr(sprPtr1, sprIdx1)

                    v[__id(sprIdArr) + sprIdx1] = sprIdx1
                    v[__id(sprZArr) + sprIdx1] = (mSpBit1 & SPR_BIT_ENABLE) ? mSpWz1 : SPR_UNUSED_Z

                    sprPid1 = mSpPid1
                    sprPid2 = PIC_SORTED_SPRITES + sprIdx1

                    //ピクチャIDを差し替える
                    @if `sprPid1 != sprPid2 bl {
                        @pic[sprPid1].setId .move(sprPid2, 1)
                        mSpPid1 = sprPid2
                    }
                }

                //降順に並べ替える
                sprZArr.sortDescending(SPR_NUM) .sync(sprIdArr)

                //ピクチャのIDを変更する
                //未使用のスプライトのピクチャIDは退避した先に留まる
                @loop SPR_NUM .dst(sprIdx2) bl {
                    sprIdx1 = v[__id(sprIdArr) + sprIdx2]
                    _getSpritePtr(sprPtr1, sprIdx1)

                    sprPid1 = PIC_SORTED_SPRITES + sprIdx1
                    sprPid2 = (mSpBit1 & SPR_BIT_ENABLE) ? (PIC_SPRITES_HEADER + sprIdx2) : (PIC_SORTED_SPRITES + sprIdx1)

                    //ピクチャIDを差し替える
                    @if sprPid1 != sprPid2 bl {
                        @pic[sprPid1].setId .move(sprPid2, 1)
                        mSpPid1 = sprPid2
                    }
                }
                //ピクチャIDを頻繁に移し替えているせいで負荷が高そうだが
                //シンプルな処理が一番なのかもしれない
            }

            //----------------------------
            //描画

            //回転に使用する三角関数
            cosRx = cos(camRx * - 1, UNIT_ANGLE, UNIT_NORMAL)
            sinRx = sin(camRx * - 1, UNIT_ANGLE, UNIT_NORMAL)
            cosRz = cos(camRz * - 1, UNIT_ANGLE, UNIT_NORMAL)
            sinRz = sin(camRz * - 1, UNIT_ANGLE, UNIT_NORMAL)

            //ループ
            //未使用を含む、全てのスプライトを更新する
            @loop SPR_NUM .dst(sprIdx1) bl {
                _getSpritePtr(sprPtr1, sprIdx1)
                //ピクチャID
                sprPid1 = mSpPid1
                //ビットフラグ
                sprBit1 = mSpBit1
                //スクリーン座標の記録位置
                sprScr1 = mSpScr1
                //本来ならピクチャがあるはず
                @if `sprPid1 <= 0 bl {
                    "Error: 無効なピクチャID"
                    @label.jump "gameEnd"
                }

                //描画フラグ
                flag = FALSE
                //使用中フラグ
                @if `sprBit1 & SPR_BIT_ENABLE bl {
                    //カメラとの差
                    lx = mSpWx1 - camX
                    ly = mSpWy1 - camY
                    lz = mSpWz1 - camZ
                    //X軸回転
                    @if `camRx % UNIT_LOOP bl {
                        ry = ly
                        rz = lz
                        lz = (rz * cosRx - ry * sinRx) / UNIT_NORMAL
                        ly = (rz * sinRx + ry * cosRx) / UNIT_NORMAL
                    }
                    //Z軸回転
                    @if `camRz % UNIT_LOOP bl {
                        rx = lx
                        ry = ly
                        lx = (rx * cosRz - ry * sinRz) / UNIT_NORMAL
                        ly = (rx * sinRz + ry * cosRz) / UNIT_NORMAL
                    }
                    //手前に近づきすぎず
                    //拡大率が1%以上で画面内に収まっているときに表示する
                    @if `between(lz, SPR_MIN_Z, SPR_MAX_Z) bl {
                        scrX = SPR_CENTER_X + lx * SPR_BASE_ANGLE / lz
                        scrY = SPR_CENTER_Y + ly * SPR_BASE_ANGLE / lz

                        scrScale = mSpScale1
                        scrScale = (sprBit1 & SPR_BIT_SCALING) ? ((SPR_BASE_SCALE * SPR_BASE_ANGLE * scrScale) / lz / 100) : scrScale
                        scrAngle = (sprBit1 & SPR_BIT_ROTATE) ? (mSpAngle1 - camRz) : 0

                        //スクリーン座標や拡大率、角度を指定した変数に入力する
                        @if `sprScr1 > 0 bl {
                            v[sprScr1..sprScr1+3] = [scrX, scrY, scrScale, scrAngle]
                        }

                        @if `scrScale > 0 &&
                            between(scrX, SPR_MIN_X, SPR_MAX_X) &&
                            between(scrY, SPR_MIN_Y, SPR_MAX_Y) bl {
                            flag = TRUE
                        }
                    }
                }

                //描画可能
                @if `flag bl {
                    //フラグON
                    @if `!(sprBit1 & SPR_BIT_SHOW) bl {
                        mSpBit1 |= SPR_BIT_SHOW
                    }
                    //ピクチャを更新する
                    @pic.move[sprPid1] .pos(scrX, scrY) .center .scale(scrScale) .trans(0) .angle(scrAngle, UNIT_ANGLE)

                //描画できない場合はその場で透明化させる
                //既に透明化している場合は何もしない
                } .elif `sprBit1 & SPR_BIT_SHOW bl {
                    //フラグOFF
                    mSpBit1 &= (-1) ^ SPR_BIT_SHOW
                    //ピクチャを透明にする
                    @pic.move[sprPid1] .pos(SPR_OUT_POS, SPR_OUT_POS) .center .scale(100) .trans(100)
                }
            }
        }
    }

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

        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, TS_MINIGAME, NUM_OF_STR)
        restoreBGM()
        fastFadeInTintOnly(1)
    }
}