: AyaanScript+ — SPACE DEFENDER 3D
:
: A simple 3D space shooter built entirely on the AS+ 3D engine.
: Showcases: native particle system, multi-light + fog, OBJ ship mesh,
: input handling, parallel lists for entity arrays, full game loop.
:
: CONTROLS
:   Arrow keys  - move ship on X/Y plane
:   SPACE       - fire laser
:   R           - restart after game over
:   ESC         - quit

const W = 800
const H = 600
gui_native "AyaanScript+ - Space Defender 3D" W H
gui_fps 60

: Engine setup
gui_3d_setup 600 400 300
gui_3d_camera 6
gui_3d_ambient 0.2
gui_3d_light -0.3 -0.6 -0.4
gui_3d_add_light 0.8 0.2 0.3 1.0 0.7 0.5
gui_3d_add_light 0.0 0.0 1.0 0.4 0.6 1.0
gui_3d_specular 0.5 24
gui_3d_fog 6 22 "#0a0a2a"

: Load ship mesh
gui_3d_load_obj "ship" "demos/assets/ship.obj"

: Game state
set player_x = 0
set player_y = 0
set lives = 3
set score = 0
set running = 1
set frame = 0
set last_space = 0
set spawn_timer = 0
set game_over = 0

: Asteroids
list ax = []
list ay = []
list az = []
list avx = []
list avy = []
list ar = []

: Bullets
list bx = []
list by = []
list bz = []

func spawn_asteroid
    rand sx -3 3
    rand sy -2 2
    rand vx -1 1
    rand vy -1 1
    set vx2 = {vx / 30}
    set vy2 = {vy / 30}
    rand sr 4 9
    set sr2 = {sr / 10}
    push ax sx
    push ay sy
    push az -18
    push avx vx2
    push avy vy2
    push ar sr2
endfunc

while running == 1
    gui_open running
    if running == 0
        break
    endif

    : starscape background
    gui_clear "#02020a"
    : random scrolling stars
    set ss = 0
    repeat 80 ss
        set six = {((ss - 1) * 47 + frame) - int(((ss - 1) * 47 + frame) / W) * W}
        set siy = {((ss - 1) * 31 + frame * 2) - int(((ss - 1) * 31 + frame * 2) / H) * H}
        gui_pixel six siy "white"
    endrepeat

    if game_over == 0
        : ===== INPUT =====
        gui_key_down "left" -> kl
        gui_key_down "right" -> kr
        gui_key_down "up" -> ku
        gui_key_down "down" -> kd
        gui_key_down "space" -> ks
        gui_key_down "esc" -> esc
        if esc == 1
            set running = 0
        endif

        if kl == 1
            set player_x = {player_x - 0.08}
        endif
        if kr == 1
            set player_x = {player_x + 0.08}
        endif
        if ku == 1
            set player_y = {player_y - 0.08}
        endif
        if kd == 1
            set player_y = {player_y + 0.08}
        endif
        : clamp player to play area
        if player_x < -3
            set player_x = -3
        endif
        if player_x > 3
            set player_x = 3
        endif
        if player_y < -2
            set player_y = -2
        endif
        if player_y > 2
            set player_y = 2
        endif

        : SPACE to shoot (edge-triggered, max 12 bullets)
        if ks == 1
            if last_space == 0
                lsize bx -> nb
                if nb < 12
                    push bx player_x
                    push by player_y
                    push bz 0
                endif
            endif
            set last_space = 1
        else
            set last_space = 0
        endif

        : ===== SPAWN ASTEROIDS =====
        set spawn_timer = {spawn_timer + 1}
        if spawn_timer > 45
            call spawn_asteroid
            set spawn_timer = 0
        endif

        : ===== UPDATE BULLETS =====
        lsize bx -> nbull
        list new_bx = []
        list new_by = []
        list new_bz = []
        set bi = 0
        repeat nbull bi
            set bk = {bi - 1}
            list_at bx bk -> tbx
            list_at by bk -> tby
            list_at bz bk -> tbz
            set tbz = {tbz - 0.6}
            if tbz > -20
                push new_bx tbx
                push new_by tby
                push new_bz tbz
            endif
        endrepeat
        lclear bx
        lclear by
        lclear bz
        foreach v in new_bx
            push bx v
        endforeach
        foreach v in new_by
            push by v
        endforeach
        foreach v in new_bz
            push bz v
        endforeach

        : ===== UPDATE ASTEROIDS + COLLISIONS =====
        lsize ax -> nast
        list new_ax = []
        list new_ay = []
        list new_az = []
        list new_avx = []
        list new_avy = []
        list new_ar = []
        set ai = 0
        repeat nast ai
            set akk = {ai - 1}
            list_at ax akk -> tax
            list_at ay akk -> tay
            list_at az akk -> taz
            list_at avx akk -> tvx
            list_at avy akk -> tvy
            list_at ar akk -> tar

            set tax = {tax + tvx}
            set tay = {tay + tvy}
            set taz = {taz + 0.12}

            set alive = 1

            : check bullet hits
            lsize bx -> nbb
            set bii = 0
            repeat nbb bii
                set bkk = {bii - 1}
                list_at bx bkk -> tbx
                list_at by bkk -> tby
                list_at bz bkk -> tbz
                set dx = {tax - tbx}
                set dy = {tay - tby}
                set dz = {taz - tbz}
                set dsq = {dx * dx + dy * dy + dz * dz}
                set rsq = {tar * tar + 0.05}
                if dsq < rsq
                    if alive == 1
                        set alive = 0
                        set score = {score + 10}
                        : spawn explosion particles
                        gui_particle_burst 400 300 12 "#ffaa33" 3 30
                    endif
                endif
            endrepeat

            : asteroid hits player?
            if alive == 1
                if taz > -0.5
                    set pdx = {tax - player_x}
                    set pdy = {tay - player_y}
                    set pdsq = {pdx * pdx + pdy * pdy}
                    if pdsq < 0.6
                        set alive = 0
                        set lives = {lives - 1}
                        if lives <= 0
                            set game_over = 1
                        endif
                    endif
                endif
                : asteroid passed player
                if taz > 1
                    set alive = 0
                endif
            endif

            if alive == 1
                push new_ax tax
                push new_ay tay
                push new_az taz
                push new_avx tvx
                push new_avy tvy
                push new_ar tar
            endif
        endrepeat
        lclear ax
        lclear ay
        lclear az
        lclear avx
        lclear avy
        lclear ar
        foreach v in new_ax
            push ax v
        endforeach
        foreach v in new_ay
            push ay v
        endforeach
        foreach v in new_az
            push az v
        endforeach
        foreach v in new_avx
            push avx v
        endforeach
        foreach v in new_avy
            push avy v
        endforeach
        foreach v in new_ar
            push ar v
        endforeach
    endif

    if game_over == 1
        gui_key_down "r" -> kr2
        if kr2 == 1
            set player_x = 0
            set player_y = 0
            set lives = 3
            set score = 0
            set frame = 0
            set game_over = 0
            lclear ax
            lclear ay
            lclear az
            lclear avx
            lclear avy
            lclear ar
            lclear bx
            lclear by
            lclear bz
        endif
        gui_key_down "esc" -> esc
        if esc == 1
            set running = 0
        endif
    endif

    : ===== RENDER 3D SCENE =====
    : reset z-buffer for this frame
    gui_3d_clear "#02020a"

    : draw asteroids
    lsize ax -> nast2
    set ri = 0
    repeat nast2 ri
        set rk = {ri - 1}
        list_at ax rk -> px
        list_at ay rk -> py
        list_at az rk -> pz
        list_at ar rk -> pr
        gui_3d_sphere px py pz pr 8 "#aa5544"
    endrepeat

    : draw bullets
    lsize bx -> nbull2
    set qi = 0
    repeat nbull2 qi
        set qk = {qi - 1}
        list_at bx qk -> px
        list_at by qk -> py
        list_at bz qk -> pz
        gui_3d_cube px py pz 0.12 "#ffff44"
    endrepeat

    : draw player ship
    if game_over == 0
        gui_3d_draw_mesh "ship" player_x player_y 0 0.6 "#44aaff"
    endif

    : particles overlay
    gui_particle_update
    gui_particle_draw

    : ===== HUD =====
    gui_text_big 20 20 "SPACE DEFENDER" "cyan" 2
    gui_text 20 60 "score:" "white"
    gui_text 90 60 score "yellow"
    gui_text 20 80 "lives:" "white"
    gui_text 90 80 lives "red"
    gui_text 20 H - 30 "ARROWS move  SPACE fire  ESC quit" "lightgray"

    if game_over == 1
        gui_fill_rect 200 220 400 160 "#000000"
        gui_rect 200 220 400 160 "red"
        gui_text_big 270 250 "GAME OVER" "red" 3
        gui_text 280 310 "Final score:" "white"
        gui_text 410 310 score "yellow"
        gui_text 250 340 "Press R to restart  |  ESC to quit" "lightgray"
    endif

    set frame = {frame + 1}
    gui_update
endwhile

gui_close
psyska -/ "Game over. Final score: {score}"
