: AyaanScript+ — DUNGEON RUNNER (first-person 3D)
:
: A real first-person 3D game: explore a procedural dungeon, collect glowing
: gems, avoid sentinels. Uses the free-look camera + collision system.
:
: CONTROLS
:   WASD        - move (W forward, S back, A/D strafe)
:   Arrow LR    - turn (yaw)
:   Arrow UD    - pitch (look up/down)
:   ESC         - quit

const W = 800
const H = 600
gui_native "AyaanScript+ - Dungeon Runner" W H
gui_fps 60

gui_3d_setup 720 400 300
gui_3d_ambient 0.25
gui_3d_light -0.3 -0.7 -0.4
gui_3d_add_light 0.5 -0.2 0.5 1.0 0.8 0.4
gui_3d_specular 0.3 16
gui_3d_fog 6 28 "#0a0814"
gui_3d_shadow on -1.5 "#080812"

: Player camera state
set px = 0
set py = 0
set pz = 0
set yaw = 0
set pitch = 0
set running = 1
set score = 0

: Dungeon — random pillars
list wx = []
list wz = []
list wcolor = []
set seed = 17
set i = 0
repeat 30 i
    rand cx -14 14
    rand cz -14 14
    rand cidx 0 3
    push wx cx
    push wz cz
    if cidx == 0
        push wcolor "#664433"
    endif
    if cidx == 1
        push wcolor "#553322"
    endif
    if cidx == 2
        push wcolor "#776655"
    endif
    if cidx == 3
        push wcolor "#444433"
    endif
endrepeat

: Gems — collectibles
list gx = []
list gz = []
list ggone = []
set j = 0
repeat 10 j
    rand gxv -14 14
    rand gzv -14 14
    push gx gxv
    push gz gzv
    push ggone 0
endrepeat

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

    : ===== INPUT =====
    gui_key_down "esc" -> esc
    if esc == 1
        set running = 0
    endif
    gui_key_down "w" -> kw
    gui_key_down "s" -> ks
    gui_key_down "a" -> ka
    gui_key_down "d" -> kd
    gui_key_down "left" -> kl
    gui_key_down "right" -> kr
    gui_key_down "up" -> ku
    gui_key_down "down" -> kdn

    : turn
    if kl == 1
        set yaw = {yaw - 0.04}
    endif
    if kr == 1
        set yaw = {yaw + 0.04}
    endif
    if ku == 1
        set pitch = {pitch - 0.03}
    endif
    if kdn == 1
        set pitch = {pitch + 0.03}
    endif

    : compute movement direction from yaw
    set fwd = 0
    set strafe = 0
    if kw == 1
        set fwd = 0.12
    endif
    if ks == 1
        set fwd = -0.10
    endif
    if ka == 1
        set strafe = -0.10
    endif
    if kd == 1
        set strafe = 0.10
    endif

    : compute new candidate position via yaw
    set sin_y = {sin(yaw)}
    set cos_y = {cos(yaw)}
    set new_px = {px + sin_y * fwd + cos_y * strafe}
    set new_pz = {pz + cos_y * fwd - sin_y * strafe}

    : Wall collision — check each pillar
    set blocked = 0
    set wi = 0
    lsize wx -> nw
    repeat nw wi
        set wk = {wi - 1}
        list_at wx wk -> tx
        list_at wz wk -> tz
        set dxc = {new_px - tx}
        set dzc = {new_pz - tz}
        set dist_sq = {dxc * dxc + dzc * dzc}
        if dist_sq < 1.2
            set blocked = 1
        endif
    endrepeat
    if blocked == 0
        set px = new_px
        set pz = new_pz
    endif

    : Gem collection
    lsize gx -> ngems
    set qi = 0
    repeat ngems qi
        set qk = {qi - 1}
        list_at ggone qk -> g_off
        if g_off == 0
            list_at gx qk -> tx
            list_at gz qk -> tz
            set dxg = {px - tx}
            set dzg = {pz - tz}
            set dg_sq = {dxg * dxg + dzg * dzg}
            if dg_sq < 0.8
                lset ggone qk 1
                set score = {score + 10}
            endif
        endif
    endrepeat

    : ===== RENDER =====
    : set free-look camera (eye 0.6 above ground)
    set cam_y = {0.6 + py}
    gui_3d_camera_pos px cam_y pz
    gui_3d_camera_yaw yaw
    gui_3d_camera_pitch pitch
    : clear with sky/dungeon gradient
    gui_3d_clear "#0a0814"
    gui_gradient_rect 0 0 W H "#1a1424" "#0a0814"

    : floor
    gui_3d_plane 0 -1.5 0 40 "#3a2a1f"

    : walls/pillars
    set wi2 = 0
    repeat nw wi2
        set wk2 = {wi2 - 1}
        list_at wx wk2 -> tx
        list_at wz wk2 -> tz
        list_at wcolor wk2 -> col
        gui_3d_cylinder tx -0.5 tz 0.7 2 12 col
    endrepeat

    : gems (uncollected)
    set qi2 = 0
    repeat ngems qi2
        set qk2 = {qi2 - 1}
        list_at ggone qk2 -> g_off
        if g_off == 0
            list_at gx qk2 -> tx
            list_at gz qk2 -> tz
            set bob = {sin(yaw * 2 + tx) * 0.15}
            set gy = {-0.5 + bob}
            gui_3d_sphere tx gy tz 0.25 10 "#44ffaa"
        endif
    endrepeat

    : center marker (exit?) — golden cone
    gui_3d_cone 0 -0.7 0 0.5 1.2 16 "#ffcc44"

    : ===== HUD =====
    gui_text_big 20 20 "DUNGEON RUNNER" "white" 2
    gui_text 20 60 "WASD move, arrows look  |  ESC quit" "lightgray"
    gui_text 20 80 "gems collected:" "white"
    gui_text 180 80 score "yellow"

    : minimap (bird's eye, top-right)
    set mmx = 620
    set mmy = 20
    set mms = 160
    gui_fill_rect mmx mmy mms mms "#080814"
    gui_rect mmx mmy mms mms "white"
    : player dot
    set mpx = {mmx + mms / 2 + px * 4}
    set mpy = {mmy + mms / 2 + pz * 4}
    gui_fill_circle mpx mpy 4 "cyan"
    : look direction
    set fdx = {sin(yaw) * 12}
    set fdz = {cos(yaw) * 12}
    set lex = {mpx + fdx}
    set lez = {mpy + fdz}
    gui_line mpx mpy lex lez "cyan"
    : pillars
    set mi = 0
    repeat nw mi
        set mk = {mi - 1}
        list_at wx mk -> tx
        list_at wz mk -> tz
        set wpx = {mmx + mms / 2 + tx * 4}
        set wpz = {mmy + mms / 2 + tz * 4}
        gui_fill_rect wpx wpz 3 3 "#aa8866"
    endrepeat
    : gems on minimap
    set gi = 0
    repeat ngems gi
        set gk = {gi - 1}
        list_at ggone gk -> g_off
        if g_off == 0
            list_at gx gk -> tx
            list_at gz gk -> tz
            set gpx = {mmx + mms / 2 + tx * 4}
            set gpz = {mmy + mms / 2 + tz * 4}
            gui_fill_circle gpx gpz 2 "#44ffaa"
        endif
    endrepeat

    gui_update
endwhile

gui_close
psyska -/ "Final score: {score} gems"
