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


cev[CEV_STARLIGHT_MANIA] .name("mg_ばくれつスターライト") {

    def {
        NUM_OF_VAR = 256
        NUM_OF_STR = 0
        NUM_OF_PIC = 32

        BASE_LAYER = 6

        PATH_FRAME  = "sm\fr"
        PATH_BACK   = "sm\ba"
        PATH_PLAYER = "sm\pl"
        PATH_BULLET = "sm\bu"
        PATH_TARGET = "sm\ta"

        PIC_HEAD     = 1
        PIC_BACK     = 2//+0_+1
        PIC_PLAYER   = 4
        PIC_BULLET   = 5
        PIC_TARGET   = 6//+0_+23
        PIC_SCORE    = 30
        PIC_HIGHSCORE= 31
        PIC_FRAME    = 32

        //実績
        ACHIEVE_SCORE = 10000

        //プレイヤーの状態
        PL_STATE_NONE = 0
        PL_STATE_ENABLE
        PL_STATE_DAMAGE
        PL_STATE_GAMEOVER

        //プレイヤーの弾丸の状態
        BU_STATE_NONE = 0
        BU_STATE_ENABLE

        //的の状態
        TA_STATE_NONE = 0
        TA_STATE_ENABLE
        TA_STATE_EXPLOSION

        //的の構造
        MT_STATE = 0
        MT_TIMER
        MT_COMBO
        MT_X
        MT_Y
        MT_VX
        MT_VY
        SIZE_OF_TA

        //その他定数
        OUT_RANGE = -320
        REF_X = 32
        REF_Y = 0
        SCR_WIDTH  = 256
        SCR_HEIGHT = 240
        STAGE_TOP = 0
        STAGE_LEFT = 0
        STAGE_BOTTOM = 220
        STAGE_RIGHT = 256

        COMBO_MAX = 8
        BASE_SCORE = 1

        PL_Y = SCR_HEIGHT - 16
        PL_RAD = 6
        PL_SPEED = 2
        PL_ATK_INTERVAL = 24
        PL_INVINCIBLE = 30
        PL_INC_DAMAGE = 2
        PL_ANIM_FRAME = 16
        PL_ANIM_FRAME_EX = 4

        BU_SPEED = 10
        BU_RAD = 8
        BU_ANIM_FRAME = 1

        TA_NUM = 24
        TA_UNIT = 10
        TA_RAD = 8
        TA_RAD_EX = 32
        TA_SPEED = 35
        TA_MIN_VY = 30
        TA_ANIM_FRAME = 4
        TA_ANIM_FRAME_EX = 6
        TA_GRAVITY = 1
        TA_DAMPING = 8
    }

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

        scoreStrPicCmd = bl {
            .topLeft
            .font("", 12) .bold
            .spacing(0, 4)
            .skin "" .nobg .noframe .noPadding
            basePicCmd
        }

        playerPicCmd = bl {
            PATH_PLAYER
            .center
            .grid(9, 1)
            basePicCmd
        }

        bulletPicCmd = bl {
            PATH_BULLET
            .center
            .grid(4, 1)
            basePicCmd
        }

        targetPicCmd = bl {
            PATH_TARGET
            .center
            .grid(8, 1)
            basePicCmd
        }
    }

    defv {
        varHead = TV_MINIGAME

        ipt
        state
        timer
        pid
        cell
        ax
        ay
        pA
        iA
        pB
        iB

        score
        scoreFlg
        gameTimer
        appearTimer
        hitSound
        bgScroll

        plState
        plTimer
        plDamage
        plLife
        plInput
        plX

        buState
        buX
        buY

        taHead

        varFoot = __id(taHead) + SIZE_OF_TA * TA_NUM
    }

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

    //的のポインタを取得する
    __fn _getTargetPtr $dvPtr $idx bl {
        v[__id($dvPtr)] = __id(taHead) + SIZE_OF_TA * ($idx)

    }

    //的の変数を初期化する
    __fn _initTargetMembers $ptr $block bl {
        $block
        v[$ptr..$ptr + SIZE_OF_TA - 1] = [$state, $timer, $combo, $x, $y, $vx, $vy]
    }

    //------------------------------------------------------------------------------------
    //開始前処理
    bl {
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, 0, 0)
        msgBottom()
        fastFadeInTintOnly(1)
        @label.jump "gameStart"
    }

    //------------------------------------------------------------------------------------
    //開始
    @label.set "gameStart"
    bl {
        //変数を初期化する
        bl {
            assignVarUsingDeclared(varHead, varFoot, 0)

            scoreFlg = TRUE
            appearTimer = 60
            hitSound = -1

            //プレイヤーの状態
            plState = PL_STATE_ENABLE
            plX = (STAGE_RIGHT - STAGE_LEFT) / 2
            plDamage = 4

            // 入力を抑制する
            plTimer = PL_ATK_INTERVAL

        }

        //ピクチャを初期化する
        bl {
            //枠
            @pic.show[PIC_FRAME] PATH_FRAME .pos(0, 0) .topLeft basePicCmd

            //背景
            @loop 2 .dst(pid) bl {
                pid += PIC_BACK
                @pic.show[pid] PATH_BACK .pos(REF_X, REF_Y) .topLeft basePicCmd
            }

            //的
            @loop TA_NUM .dst(pid) bl {
                pid += PIC_TARGET
                @pic.show[pid] .pos(OUT_RANGE, OUT_RANGE) .cell(0) targetPicCmd
            }

            //プレイヤー
            @pic.show[PIC_PLAYER] .pos(OUT_RANGE, OUT_RANGE) .cell(0) playerPicCmd
            @pic.show[PIC_BULLET] .pos(OUT_RANGE, OUT_RANGE) .cell(0) bulletPicCmd
        }

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

            //----------------------------
            //ゲームタイマー
            gameTimer += 1

            //----------------------------
            //プレイヤー
            @if plState == PL_STATE_NONE bl {
                cell = 0

            } .elif plState == PL_STATE_ENABLE bl {
                easyAnimation(cell, TRUE, 1, 2, gameTimer, PL_ANIM_FRAME)

                //移動
                @key.input .dst(ax) .left
                @key.input .dst(ay) .right
                ipt = (ay ? 1 : 0) - (ax ? 1 : 0)
                @if `ipt bl {
                    plX = clamp(plX + ipt * PL_SPEED, STAGE_LEFT + PL_RAD, STAGE_RIGHT - PL_RAD)
                }

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

                } .elif `ipt bl {
                    plTimer = PL_ATK_INTERVAL
                    buState = BU_STATE_ENABLE
                    V2_set(buX, plX, PL_Y)
                    @se.play "Cancel1" .opt(100, 250, 50)
                }

                //無敵時間
                @if plLife > 0 bl {
                    plLife -= 1
                }

                //ダメージ
                @key.input .dst(ipt) .shift
                @if `ipt bl {
                    plState = PL_STATE_DAMAGE
                    plTimer = 0
                    plLife = 0
                    plInput = 0
                    @se.play "Damage1" .opt(80, 100, 50)
                    @se.play "voice_aa" .opt(100, 100, 50)
                }

            } .elif plState == PL_STATE_DAMAGE bl {
                easyAnimation(cell, TRUE, 3, 4, gameTimer, PL_ANIM_FRAME)

                //連打
                @key.input .dst(ipt) {
                    .decision
                    .down
                }
                plInput = ipt ? plInput + 1 : 0
                @if `plInput == 1 bl {
                    plLife += 1
                    //復帰
                    @if plLife >= plDamage bl {
                        plState = PL_STATE_ENABLE
                        plTimer = 0
                        plDamage += PL_INC_DAMAGE
                        plLife = PL_INVINCIBLE
                        @se.play "Evade1" .opt(100, 120, 50)

                    } .else bl {
                        @se.play "Blow1" .opt(100, 150, 50)
                    }
                }

                //ゲームオーバー判定
                plTimer += 1
                @if plTimer >= 60 * 4 bl {
                    cell = 5
                    plState = PL_STATE_GAMEOVER
                    plTimer = 0
                    @se.play "explo1" .opt(100, 120, 50)

                //カウントダウン
                } .elif `plTimer > 0 && plTimer % 60 == 0 bl {
                    @se.play "Cancel2" .opt(80, 90, 50)
                }

            } .elif plState == PL_STATE_GAMEOVER bl {
                easyAnimation(cell, FALSE, 5, 9, plTimer, PL_ANIM_FRAME_EX)

                plTimer += 1
                @if plTimer > 60 * 2 bl {
                    //もう一回やる？
                    replayProcess("gameStart", "gameEnd")

                }
            }

            V2_set(ax, REF_X + plX, REF_Y + PL_Y)
            @pic.show[PIC_PLAYER] .pos(ax, ay) .cell(cell) playerPicCmd

            //----------------------------
            //弾丸
            @if buState == BU_STATE_NONE bl {
                cell = 0

            } .elif buState == BU_STATE_ENABLE bl {
                easyAnimation(cell, TRUE, 1, 4, gameTimer, BU_ANIM_FRAME)

                buY -= BU_SPEED

                //画面外判定
                @if buY < STAGE_TOP bl {
                    buState = BU_STATE_NONE
                }
            }

            V2_set(ax, REF_X + buX, REF_Y + buY)
            @pic.show[PIC_BULLET] .pos(ax, ay) .cell(cell) bulletPicCmd

            //----------------------------
            //的を出現させる
            appearTimer -= 1

            @if appearTimer <= 0 bl {
                //2分ほどで最速になる
                $max = 60 * 60 * 2
                appearTimer = lerp(30, 10, min(gameTimer, $max), $max)

                @loop TA_NUM .dst(iA) bl {
                    _getTargetPtr(pA, iA)
                    @if `v[pA + MT_STATE] != TA_STATE_NONE bl {
                        @continue
                    }

                    _initTargetMembers(pA, bl {
                        $state = TA_STATE_ENABLE
                        $x = rnd(STAGE_LEFT, STAGE_RIGHT) * TA_UNIT
                        $y = STAGE_TOP
                        $vx = [-1, 1][rnd(0, 1)] * TA_SPEED
                        $vy = 0
                    } )

                    @break
                }
            }

            //----------------------------
            //的
            @loop TA_NUM .dst(iA) bl {
                _getTargetPtr(pA, iA)
                @if `v[pA + MT_STATE] == TA_STATE_NONE bl {
                    @continue
                }

                v[pA + MT_TIMER] += 1

                pid = PIC_TARGET + iA
                timer = v[pA + MT_TIMER]
                state = v[pA + MT_STATE]

                @if state == TA_STATE_ENABLE bl {
                    easyAnimation(cell, TRUE, 1, 4, timer, TA_ANIM_FRAME)

                    //移動
                    v[pA + MT_X] += v[pA + MT_VX]
                    v[pA + MT_Y] += v[pA + MT_VY]

                    //重力
                    v[pA + MT_VY] += TA_GRAVITY

                    //地面と反射する
                    @if `v[pA + MT_Y] > STAGE_BOTTOM * TA_UNIT bl {
                        v[pA + MT_Y] = STAGE_BOTTOM * TA_UNIT
                        v[pA + MT_VY] *= -1

                        //勢いが足りないと自壊する
                        @if `abs(v[pA + MT_VY]) < TA_MIN_VY bl {
                            v[pA + MT_STATE] = TA_STATE_EXPLOSION
                            v[pA + MT_TIMER] = 0
                            v[pA + MT_COMBO] = 0

                        } .else bl {
                            v[pA + MT_VY] += TA_DAMPING

                        }

                    }

                    //画面端で反射する
                    @if `v[pA + MT_X] < (STAGE_LEFT + TA_RAD) * TA_UNIT bl {
                        v[pA + MT_X] = (STAGE_LEFT + TA_RAD) * TA_UNIT
                        v[pA + MT_VX] *= -1
                    }
                    @if `v[pA + MT_X] > (STAGE_RIGHT - TA_RAD) * TA_UNIT bl {
                        v[pA + MT_X] = (STAGE_RIGHT - TA_RAD) * TA_UNIT
                        v[pA + MT_VX] *= -1
                    }

                    //自機弾との衝突判定
                    $rad = (BU_RAD + TA_RAD)
                    V2_set(ax,
                        buX - v[pA + MT_X] / TA_UNIT,
                        buY - v[pA + MT_Y] / TA_UNIT,
                    )
                    @if `buState == BU_STATE_ENABLE && ax * ax + ay * ay < $rad * $rad bl {
                        v[pA + MT_STATE] = TA_STATE_EXPLOSION
                        v[pA + MT_TIMER] = 0
                        v[pA + MT_COMBO] = 0

                        score += 1 * BASE_SCORE
                        scoreFlg = TRUE
                        hitSound = max(hitSound, v[pA + MT_COMBO])

                        buState = BU_STATE_NONE

                    //自機との衝突判定
                    } .else bl {
                        $rad = (PL_RAD + TA_RAD)
                        V2_set(ax,
                            plX  - v[pA + MT_X] / TA_UNIT,
                            PL_Y - v[pA + MT_Y] / TA_UNIT,
                        )

                        @if invincibleSwitch.isOff bl {
                            @if `plState == PL_STATE_ENABLE && plLife <= 0 && ax * ax + ay * ay < $rad * $rad bl {
                                //被弾
                                plState = PL_STATE_DAMAGE
                                plTimer = 0
                                plLife = 0
                                plInput = 0
                                @se.play "Damage1" .opt(80, 100, 50)
                                @se.play "voice_aa" .opt(100, 100, 50)
                            }
                        }
                    }

                } .elif state == TA_STATE_EXPLOSION bl {
                    easyAnimation(cell, FALSE, 5, 8, timer, TA_ANIM_FRAME_EX)

                    //他の的との衝突判定
                    @loop TA_NUM .dst(iB) bl {
                        _getTargetPtr(pB, iB)
                        @if `v[pB + MT_STATE] != TA_STATE_ENABLE bl {
                            @continue
                        }

                        //爆発判定は少しずつ広がる
                        ipt = lerp(TA_RAD, TA_RAD_EX, timer, TA_ANIM_FRAME_EX * 4) + TA_RAD
                        V2_set(ax,
                            (v[pB + MT_X] - v[pA + MT_X]) / TA_UNIT,
                            (v[pB + MT_Y] - v[pA + MT_Y]) / TA_UNIT,
                        )

                        @if `ax * ax + ay * ay < ipt * ipt bl {
                            //誘爆
                            v[pB + MT_STATE] = TA_STATE_EXPLOSION
                            v[pB + MT_TIMER] = 0
                            v[pB + MT_COMBO] = min(v[pA + MT_COMBO] + 1, COMBO_MAX)

                            //スコア加算
                            ipt = v[pB + MT_COMBO]

                            score += pow(2, ipt) * BASE_SCORE
                            scoreFlg = TRUE

                            hitSound = max(hitSound, ipt)
                        }
                    }

                    //時間経過で消滅する
                    @if timer > TA_ANIM_FRAME_EX * 4 bl {
                        cell = 0
                        v[pA + MT_STATE] = TA_STATE_NONE

                    }

                }

                V2_set(ax,
                    REF_X + v[pA + MT_X] / TA_UNIT,
                    REF_Y + v[pA + MT_Y] / TA_UNIT
                )
                @pic.show[pid] .pos(ax, ay) .cell(cell) targetPicCmd
            }

            //----------------------------
            //コンボ効果音
            @if `hitSound >= 0 bl {
                @if hitSound >= COMBO_MAX bl {
                    @se.play "Decision2" .opt(80, 120, 50)

                } .else bl {
                    //ドレミファソラシド
                    ipt = [100, 112, 126, 133, 150, 168, 189, 200][hitSound]
                    @se.play "Cursor2" .opt(80, ipt, 50)
                }
                hitSound = -1
            }

            //----------------------------
            //背景スクロール
            bgScroll += 2
            bgScroll %= SCR_WIDTH * 10
            @loop 2 .dst(iA) bl {
                pid = PIC_BACK + iA
                V2_set(ax,
                    REF_X - SCR_WIDTH + (bgScroll / 10 + SCR_WIDTH * iA) % (SCR_WIDTH * 2),
                    REF_Y
                )
                @pic.move[pid] .pos(ax, ay) .topLeft
            }

            //----------------------------
            //スコアの更新と表示
            @if `scoreFlg bl {
                scoreFlg = FALSE
                @if `score > starlightManiaScore bl {
                    starlightManiaScore = score
                }
                checkSetAchievement(achievedStarlight, score >= ACHIEVE_SCORE)
                @pic.strpic [PIC_SCORE] __str("SCORE", NEWLINE, "\", score) .pos(48 + REF_X, 8 + REF_Y) scoreStrPicCmd
                @pic.strpic [PIC_HIGHSCORE] __str("HISCORE", NEWLINE, "\", starlightManiaScore) .pos(144 + REF_X, 8 + REF_Y) scoreStrPicCmd
            }
        }
    }

    //------------------------------------------------------------------------------------
    //終了する
    @label.set "gameEnd"
    bl {
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, 0, 0)
        fastFadeInTintOnly(1)
    }
}