: AyaanScript+ — JUMP RUNNER 3D
:
: A real 3D platformer with gravity, jumping, AABB platform collision,
: collectible coins, and a third-person follow camera.
:
: CONTROLS
:   WASD / Arrows  - move
:   SPACE          - jump
:   Q / E          - rotate camera left/right
:   R              - restart
:   ESC            - quit

const W = 800
const H = 600
gui_native "AyaanScript+ - Jump Runner 3D" W H
gui_fps 60

: Engine setup — bright outdoor scene
gui_3d_setup 720 400 300
gui_3d_ambient 0.4
gui_3d_light -0.4 -0.7 -0.3
gui_3d_add_light 0.5 0.0 0.5 1.0 0.9 0.7
gui_3d_specular 0.2 16
gui_3d_fog 25 60 "#87a8c8"
gui_3d_shadow on -0.05 "#101820"

: ========== LEVEL DATA ==========
: Each platform: x, y, z, width, height, depth, color
: Platforms form a path from start (0,0,0) toward the goal
list plx = [0, 4, 8, 12, 12, 16, 20, 22, 26]
list ply = [0, 0, 0, 0, 2, 2, 2, 4, 5]
list plz = [0, 0, -2, 0, 2, 5, 5, 8, 10]
list plw = [4, 3, 3, 3, 3, 2, 3, 2, 5]
list plh = [1, 1, 1, 1, 1, 1, 1, 1, 1]
list pld = [4, 3, 3, 3, 3, 2, 3, 2, 5]
list plc = ["#669944", "#558833", "#778855", "#669944", "#558833", "#aa8844", "#778855", "#aa8844", "#cc8855"]

: Coins along the path
list coinx = [4, 8, 12, 16, 20, 22, 26]
list coiny = [1.5, 1.5, 2.5, 3.5, 3.5, 5.5, 6.5]
list coinz = [0, -2, 2, 5, 5, 8, 10]
list cgone = [0, 0, 0, 0, 0, 0, 0]

: Goal flag pole at (26, 5, 10)
set goal_x = 26
set goal_y = 6
set goal_z = 10

: ========== PLAYER STATE ==========
set px = 0
set py = 2
set pz = 0
set vy = 0
set on_ground = 0
set cam_yaw = 0
set score = 0
set lives = 3
set won = 0

: physics constants
const GRAVITY = -0.024
const JUMP_VEL = 0.45
const MOVE_SPEED = 0.13

set running = 1
set frame = 0
set last_space = 0
set last_r = 0

func reset_player
    set px = 0
    set py = 2
    set pz = 0
    set vy = 0
    set lives = 3
    set score = 0
    set won = 0
    : reset coins
    set ci = 0
    repeat 7 ci
        set ck = {ci - 1}
        lset cgone ck 0
    endrepeat
endfunc

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

    : ===== INPUT =====
    gui_key_down "esc" -> esc
    if esc == 1
        set running = 0
    endif

    if won == 0
        if lives > 0
            gui_key_down "w" -> kw
            gui_key_down "s" -> ks
            gui_key_down "a" -> ka
            gui_key_down "d" -> kd
            gui_key_down "up" -> kup
            gui_key_down "down" -> kdn
            gui_key_down "left" -> kl
            gui_key_down "right" -> kr
            gui_key_down "space" -> kspace
            gui_key_down "q" -> kq
            gui_key_down "e" -> ke

            : camera rotation (q/e)
            if kq == 1
                set cam_yaw = {cam_yaw - 0.03}
            endif
            if ke == 1
                set cam_yaw = {cam_yaw + 0.03}
            endif

            : movement input — combine WASD + arrow keys
            set in_fwd = 0
            set in_strafe = 0
            if kw == 1
                set in_fwd = 1
            endif
            if kup == 1
                set in_fwd = 1
            endif
            if ks == 1
                set in_fwd = -1
            endif
            if kdn == 1
                set in_fwd = -1
            endif
            if ka == 1
                set in_strafe = -1
            endif
            if kl == 1
                set in_strafe = -1
            endif
            if kd == 1
                set in_strafe = 1
            endif
            if kr == 1
                set in_strafe = 1
            endif

            : convert input to world delta using camera yaw
            set sin_y = {sin(cam_yaw)}
            set cos_y = {cos(cam_yaw)}
            set dx = {(sin_y * in_fwd + cos_y * in_strafe) * MOVE_SPEED}
            set dz = {(cos_y * in_fwd - sin_y * in_strafe) * MOVE_SPEED}

            : ===== APPLY MOVEMENT =====
            set px = {px + dx}
            set pz = {pz + dz}

            : ===== GRAVITY =====
            set vy = {vy + GRAVITY}
            set py = {py + vy}

            : ===== JUMP =====
            if kspace == 1
                if last_space == 0
                    if on_ground == 1
                        set vy = JUMP_VEL
                        set on_ground = 0
                    endif
                endif
                set last_space = 1
            else
                set last_space = 0
            endif

            : ===== PLATFORM COLLISION =====
            : Find highest platform top below player
            set best_top = -99999
            set pi = 0
            repeat 9 pi
                set pk = {pi - 1}
                list_at plx pk -> bx
                list_at ply pk -> by
                list_at plz pk -> bz
                list_at plw pk -> bw
                list_at plh pk -> bh
                list_at pld pk -> bd
                platform_top px pz bx by bz bw bh bd -> top
                if top > best_top
                    if py > top - 0.5
                        set best_top = top
                    endif
                endif
            endrepeat

            set on_ground = 0
            if best_top > -99000
                if py < {best_top + 0.6}
                    if vy <= 0
                        set py = {best_top + 0.5}
                        set vy = 0
                        set on_ground = 1
                    endif
                endif
            endif

            : Fell into the void
            if py < -8
                set lives = {lives - 1}
                set px = 0
                set py = 2
                set pz = 0
                set vy = 0
            endif

            : ===== COIN COLLECTION =====
            set qi = 0
            repeat 7 qi
                set qk = {qi - 1}
                list_at cgone qk -> g_off
                if g_off == 0
                    list_at coinx qk -> tx
                    list_at coiny qk -> ty
                    list_at coinz qk -> tz
                    set ddx = {px - tx}
                    set ddy = {py - ty}
                    set ddz = {pz - tz}
                    set ddsq = {ddx*ddx + ddy*ddy + ddz*ddz}
                    if ddsq < 0.9
                        lset cgone qk 1
                        set score = {score + 10}
                    endif
                endif
            endrepeat

            : ===== WIN CHECK =====
            set wdx = {px - goal_x}
            set wdz = {pz - goal_z}
            set wdsq = {wdx*wdx + wdz*wdz}
            if wdsq < 4
                if py > {goal_y - 2}
                    set won = 1
                endif
            endif
        endif
    endif

    : ===== RESTART =====
    gui_key_down "r" -> kr2
    if kr2 == 1
        if last_r == 0
            call reset_player
        endif
        set last_r = 1
    else
        set last_r = 0
    endif

    : ===== RENDER =====
    : Sky background
    gui_gradient_rect 0 0 W H "#87a8c8" "#5a7090"

    : Third-person follow camera
    gui_3d_camera_follow px py pz cam_yaw 6 3
    gui_3d_clear "#87a8c8"

    : Draw all platforms
    set ri = 0
    repeat 9 ri
        set rk = {ri - 1}
        list_at plx rk -> bx
        list_at ply rk -> by
        list_at plz rk -> bz
        list_at plw rk -> bw
        list_at pld rk -> bd
        list_at plc rk -> bcol
        gui_3d_cube bx by bz bw bcol
    endrepeat

    : Draw coins (animated spinning billboards)
    set yi = 0
    repeat 7 yi
        set yk = {yi - 1}
        list_at cgone yk -> g_off
        if g_off == 0
            list_at coinx yk -> tx
            list_at coiny yk -> ty
            list_at coinz yk -> tz
            set bob = {sin(frame * 0.05 + tx) * 0.2}
            set ty2 = {ty + bob}
            gui_3d_billboard tx ty2 tz 0.5 "#ffdd33"
        endif
    endrepeat

    : Goal flag — golden cylinder + spinning top
    gui_3d_cylinder goal_x {goal_y - 0.5} goal_z 0.1 2.0 8 "#ddbb44"
    set flag_rot = {frame * 0.04}
    set fx = {goal_x + cos(flag_rot) * 0.5}
    set fz = {goal_z + sin(flag_rot) * 0.5}
    gui_3d_cube fx {goal_y + 0.3} fz 0.5 "#ff4488"

    : Draw player (orb)
    if lives > 0
        gui_3d_sphere px py pz 0.4 10 "#44aaff"
    endif

    : ===== HUD =====
    gui_text_big 20 20 "JUMP RUNNER" "white" 2
    gui_text 20 60 "score:" "white"
    gui_text 80 60 score "yellow"
    gui_text 20 78 "lives:" "white"
    gui_text 80 78 lives "red"
    gui_text 20 H - 30 "WASD move  SPACE jump  Q/E camera  R reset  ESC quit" "lightgray"

    if won == 1
        gui_fill_rect 200 220 400 160 "#000000"
        gui_rect 200 220 400 160 "yellow"
        gui_text_big 290 250 "YOU WIN!" "yellow" 3
        gui_text 290 310 "Score:" "white"
        gui_text 360 310 score "yellow"
        gui_text 270 340 "Press R to play again" "lightgray"
    endif

    if lives <= 0
        if won == 0
            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 270 320 "Press R to restart" "lightgray"
        endif
    endif

    set frame = {frame + 1}
    gui_update
endwhile

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