NaaLaa
Tiny Golf - Printable Version

+- NaaLaa (https://www.naalaa.com/forum)
+-- Forum: NaaLaa (https://www.naalaa.com/forum/forum-1.html)
+--- Forum: NaaLaa 7 Code (https://www.naalaa.com/forum/forum-4.html)
+--- Thread: Tiny Golf (/thread-108.html)

Pages: 1 2


Tiny Golf - 1micha.elok - 03-21-2024

TINY GOLF

           
click the image to zoom in
Edit : added a hole-in-one

 Description
 Help Mario to make a hole-in-one
 and achieve The World Record
 of The Tiny Golf

 Made with  
 N7_240310

 Controls :
 1. LEFT click and drag from O to aim
 2. ENTER to swing the golf club
 3. ESC to continue / quit

 Acknowledgements :
 - polygon, polyline.n7, sfx.n7 by Marcus
 - some sound effects are copied from the "Pool" game by Kevin
   hit_ball_sound, oh_no_sound
 - draggable point on a polyline by Kevin
   https://naalaa.com/forum/thread-90-post-493.html#pid493
 - sprite https://www.spriters-resource.com/game_boy_gbc/mariogolf/sheet/12294/

Code:
'-----------------------------------
' TINY GOLF
' =========
' Help Mario to make a hole-in-one
' and achieve The World Record
' of The Tiny Golf
'
' Made with N7_240310
'
' Controls :
' 1. LEFT click and drag from O to aim
' 2. ENTER to swing the golf club
' 3. ESC to continue / quit
'
' Acknowledgements :
' - polygon, polyline.n7, sfx.n7 by Marcus
' - some sound effects are copied from the "Pool" game by Kevin
'   hit_ball_sound
'   oh_no_sound
' - draggable point on a polyline by Kevin
'   https://naalaa.com/forum/thread-90-post-493.html#pid493
' - sprite https://www.spriters-resource.com/game_boy_gbc/mariogolf/sheet/12294/
'----------------------------------

'-----------------
' INITIALIZATION
'-----------------
#win32
include "assets/sound_effect.n7"
include "polyline.n7"
set window "TINY GOLF",250,180,false,3
set redraw off

'color definition
visible black_alpha = [0,0,0,24]
visible black       = [0,0,0]
visible white       = [255,255,255]
visible gray        = [150,150,150]
visible green_      = [0,80,0]
visible green       = [51,153,10,24]
visible yellow      = [200,200,0]

'cartesian coordinates
visible ox = 50,oy = 165    'origin point
axy = 360-45                'angle between x and y-axis
length = 150                'length of axis 

'Polygon
grass =
[
    ox,oy,
    length+ox,oy,
    ox+length*cos(rad(axy))+length-80 ,oy+length*sin(rad(axy)),
    ox+length*cos(rad(axy))          ,oy+length*sin(rad(axy))
]

'PolyLine Path
visible points = []
ResetPoints()
path = PolyLine(points,0)'0 = opened path
distance = 0
speed = 5

'Player
visible Player = []
Player.standby = 0
Player.face = 0
Player.swing = 0
Player.x = ox-25
Player.y = oy-30

'Sound effect
hit_ball_sound = CreateNoiseSfx(0.1, 1.05, 0, 14200)'(duration, pitch, fadeOut, sampleRate)
oh_no_sound = CreateSineSfx(1.7,600,310,0.215,11600)

'Other initial values
hit = false
drawline = false
stay = false
visible title = true
visible timer = []
timer.Start = clock()
visible i=0,j=0 'counter
visible p10,p11,p20 = ox; p21=oy
score = 50
holex = (144+224)/2
holey = 70

'------------
' MAIN LOOP
'------------
while not keydown(KEY_ESCAPE,true)
    '----------------------
    '     title screen
    '----------------------
    if title=true then Action(4,0,0)

    '----------------------
    '   screen layout
    '----------------------
    '1. golf course
    set color green; draw poly grass,1
    set color white; draw poly grass
    set caret ox,oy;wln "O"
    set color black; draw ellipse holex,holey,3,2,1
    set color white; draw ellipse holex,holey,3,2
       
    'supporting lines
    'set color yellow; draw line 0,70,width(primary),70
    'set color yellow; draw line 144,0,144,height(primary)
    'set color yellow; draw line 224,0,224,height(primary)
    'set color yellow; draw line ox,oy,holex,holey
    'set color yellow; draw line 117,0,117,height(primary)

    '3. Score
    set color white; set caret 10,40; wln "Timer"; wln round(score)
    if round(score) >= 1 then
        score = score - 0.05
    else
        free distance
        hit = false
        Say("TIME OUT..ESC")
        redraw
        play sound oh_no_sound       
        do;wait 1;until keydown(KEY_ESCAPE,true)
        ResetPoints()
        score = 50
    endif        
       
    '----------
    ' Control
    '----------
    'Left click mouse
    if mousebutton(0) then
        points[1][0] = mousex()
        points[1][1] = mousey()
       
        'use random number, wind blowing perhaps :-)
        p10 = points[1][0]+rnd(5,10)
        p11 = points[1][1]+rnd(5,10)
        drawline = true
    else
        drawline = false
    endif  

    'set how high your golf ball
    set color black_alpha; cls 'clear screen
    if drawline = true or stay then
        set color yellow
        draw line points[0][0],points[0][1],points[1][0],points[1][1]
        draw rect points[1][0] - 8, points[1][1] - 8,16,16 
        Say("ENTER to shoot")
        stay = true
    else
        Say("Drag point from O")       
    endif

    ' 2. ENTER to move ball along the PolyLine path
    if keydown(KEY_RETURN,true) then
        Action(3,0,2)
        play sound hit_ball_sound
        hit = not hit 'toggle on/off
        stay = false
    endif   
    if hit then
        points[0]=[ox,oy]
        points[1]=[p10,p11]
        points[2]=[p20,p21]
       
        'points[2] coordinate
        p20 =  p10*2
        'p21 is on a line between (ox,oy) and (holex,holey)
        'the equation of the line is y = -0.71x + 200.45
        p21 = -0.71*p20 + 200.45       
       
        path = PolyLine(points,0)'0 = opened_path
        distance = (distance + speed)%path.GetLength()
        pos = path.GetPoint(distance, 1) '1=curved
       
        draw ellipse pos[0], pos[1], 2, 2, 1 '1 = filled ellipse
       
        set caret width(primary)/2, height(primary) - 25
        set color white;draw image Player.swing,Player.x,Player.y,2 'stay at the position during the shoot

        'stop the ball and clear the remaining path's distance
        if round(distance) > 0.95*path.GetLength()then
            free distance
            hit = false
            Say("Drag square from O")
        endif
                       
        'collision detection between the ball and the hole
        '1.distance between the center of the ball and the center of the hole
        cbh = sqr(pow(holex-pos[0],2)+pow(holey-pos[1],2))
        if cbh<(2+3) then
            Say("Hole-in-one")
            PlayTune(1)
            free distance
            redraw
            hit = false
            do;wait 1;until keydown(KEY_RETURN,true) 'pause
        endif

    endif

    '-------------------------------
    ' Standy by
    '-------------------------------
    if hit=false then Action(0,0,1)
       
    redraw
    fwait 30
wend


'-----------
' FUNCTIONS
'-----------
function Action(type,cell1,cell2)
    set color white
    select type
    case 0 'stand by position
        Player.standby = loadimage("assets/standby.png",2,1)
        timer.Duration = (clock() - timer.Start)/1000
        if round(timer.Duration)%2 = 0 then
            i=cell2
        else
            i=cell1
        endif
        draw image Player.standby, Player.x, Player.y, i
    case 1 'Mario's face animation
        Player.face = loadimage("assets/say.png",3,1)
        draw image Player.face, 20,5,j
        timer.Duration = (clock() - timer.Start)/1000
        if round(timer.Duration)%2 = 0 then
            if j <= 1 then
                j = j+1
            endif
        else
            j = 0
        endif
    case 3 'swing the golf club
        for k = cell1 to cell2
            set color black
               draw rect Player.x,Player.y,width(Player.standby),height(Player.standby),1
            set color white
            Player.swing = loadimage("assets/swing.png",3,1)
            draw image Player.swing, Player.x, Player.y,k
            redraw
            wait 250
        next
        set color black; draw rect Player.x,Player.y,width(Player.standby),height(Player.standby),1
        redraw
    case 4'title screen
        title = false
        set color white
        set caret width(primary)/2,0
        center "---------"
        center "Tiny Golf"
        center "---------"
        center
        center "Help Mario"
        center "to make a hole-in-one"
        center "and achieve"
        center "The World Record"
        center "of The Tiny Golf"
        center
        center "Press ESC to continue"
        redraw
        PlayTune(1)
        do; wait 1; until keydown(KEY_ESCAPE,true)
    endsel
endfunc

'Reset draggable path points
function ResetPoints()
    points[0] = [ox,oy]
    points[1] = [ox,oy]
    points[2] = [ox,oy]
endfunc

function Say(message)
    set color green_; draw rect 0,0,width(primary),35,1 '1 = filled rectangle
    set color white; set caret width(primary)/2,15; center message

    'Mario's face
    Action(1,0,2)
    draw line 0,35,width(primary),35
endfunc



RE: Tiny Golf - johnno56 - 03-21-2024

This is VERY cool... Nicely done!

It took me a couple of shots to get the hang of the controls... but, after that... I played quite poorly... Normal for me... lol

Looking forward to further updates... Wink


RE: Tiny Golf - Marcus - 03-21-2024

My first shot was a hole-in-one Smile


RE: Tiny Golf - johnno56 - 03-21-2024

Oh... Tongue


RE: Tiny Golf - 1micha.elok - 03-22-2024

@Marcus
There are two possibilities :
Either this tiny golf is too easy for you ....or you are actually a professional golf player  Big Grin
.... just one shot in the first attempt and you made a hole-in-one. Awesome.

@Johnno
Next update ( I haven't set a dateline yet ..... lol )
1. Random position of the hole
    Random position of the player
2. Somethings will interuppt you in the middle of the game :
    Birds or hamsters that catch your golf ball  
    A strange guy who tries to steal your golf ball
    Aliens / UFO that try to pick you up into their spaceship 
    ....mmm.... you can shoot them with the golf ball
3. Wind direction ( left or right ) that will make your golf ball goes against your will
4. Implement N7 features : highscore, json, use background story from a text file
5. .... still thinking..... lol 

Cool


RE: Tiny Golf - johnno56 - 03-22-2024

Tiny golf with aliens? Who would have imagined? lol Sounds like fun!


RE: Tiny Golf - 1micha.elok - 03-25-2024

(03-22-2024, 04:33 AM)johnno56 Wrote: Tiny golf with aliens? Who would have imagined? lol  Sounds like fun!

Some Updates - Day 1
       
click the image to zoom in some updates

Changelog
1. Random position of the hole. DONE
   Random position of the player. DONE
2. Somethings will interuppt you in the middle of the game.
  Birds or hamsters that catch your golf ball  TOBE
  A strange guy who tries to steal your golf ball  TOBE
  Aliens / UFO that try to pick you up into their spaceship  TOBE
  ....mmm.... you can shoot them with the golf ball  TOBE
3. Wind direction factor. DONE
4. Implement N7 features :
  highscore. DONE
  json. TOBE
  text file. DONE

Dateline
In 5 days (before Friday, 29 March 2024)

Code:
'-----------------------------------
' TINY GOLF - DAY 1
' =================
' Help Mario to make a hole-in-one
' and achieve The World Record
' of The Tiny Golf
'
' Made with N7_240310
'
' NEXT UPDATE :
'1. Random position of the hole. DONE
'   Random position of the player. DONE
'2. Somethings will interuppt you in the middle of the game :
'   Birds or hamsters that catch your golf ball 
'   A strange guy who tries to steal your golf ball
'   Aliens / UFO that try to pick you up into their spaceship
'   ....mmm.... you can shoot them with the golf ball
'3. Wind direction factor. DONE
'4. Implement N7 features :
'   highscore. DONE
'   json
'   text file. DONE
'
' Controls :
' 1. LEFT click and drag from O to aim
' 2. ENTER to swing the golf club
' 3. ESC to continue / quit
'
' Acknowledgements :
' - polygon, polyline.n7, sfx.n7 by Marcus
' - some sound effects are copied from the "Pool" game by Kevin
'   hit_ball_sound, oh_no_sound
' - draggable point on a polyline by Kevin
'   https://naalaa.com/forum/thread-90-post-493.html#pid493
' - Highscore example
'   Converted to N7 by Marcus, original N6 by JSM.
' - discussion on text file, thanks to Tomaaz and Marcus
'   https://www.naalaa.com/forum/thread-109.html
' - sprite
'   https://www.spriters-resource.com/game_boy_gbc/mariogolf/sheet/12294/
'   https://www.cleanpng.com/png-golf-golf-course-flag-pole-green-white-ball-pictur-7951521
'----------------------------------

'-----------------
' INITIALIZATION
'-----------------
#win32
include "assets/sound_effect.n7"
include "polyline.n7"
include "highscore.n7"
set window "TINY GOLF",250,180,false,3
set redraw off
randomize clock()

'color definition
visible black_alpha = [0,0,0,24]
visible black       = [0,0,0]
visible white       = [255,255,255]
visible gray        = [150,150,150]
visible green_      = [0,80,0]
visible green       = [51,153,10,24]
visible yellow      = [200,200,0]

'Golf course
visible ox = 50,oy = 165     'origin point
axy = 360-45                 'angle between x and y-axis
length = 150                 'length of axis 
hole = [x:rnd(149,219),y:70] 'random x position of hole 

'Polygon
grass =
[
    ox,oy,
    length+ox,oy,
    ox+length*cos(rad(axy))+length-80 ,oy+length*sin(rad(axy)),
    ox+length*cos(rad(axy))          ,oy+length*sin(rad(axy))
]

'PolyLine Path
visible points = []
visible p10,p11,p20 = ox; p21=oy
ResetPoints()
path = PolyLine(points,0)'0 = opened path
distance = 0
speed = 5

'Player
visible Player = []
Player.x = ox -25
Player.y = oy -30
Player.standby = 0
Player.face = 0
Player.swing = 0
Player.name = 0
Player.score = 50

'Sound effect (duration, pitch, fadeOut, sampleRate)
hit_ball_sound = CreateNoiseSfx(0.1, 1.05, 0, 14200)
oh_no_sound = CreateSineSfx(1.7,600,310,0.215,11600)

'highscore
visible hiFilename = "assets/highscore.txt"

'flag
flag = []
flag.img = loadimage("assets/flag.png",2,1)
flag.x = hole.x-width(flag.img)/2
flag.y = hole.y-height(flag.img) 
cell = 1
wind = 0

'Other initial values
hit = false
drawline = false
stay = false
visible title = true
visible timer = []; timer.Start = clock()
visible i=0,j=0 'counter

'------------
' MAIN LOOP
'------------
while not keydown(KEY_ESCAPE,true)
    '----------------------
    '     title screen
    '----------------------
    if title=true then
        Action(4,0,0) 'background story
        Action(5,0,0) 'wall of fame
        Action(6,0,0) 'input name
    endif
   
    '----------------------
    '   screen layout
    '----------------------
    '1. golf course
    set color green; draw poly grass,1
    set color white; draw poly grass
    set caret ox,oy;wln "O"
    set color black; draw ellipse hole.x,hole.y,3,2,1
    set color white; draw ellipse hole.x,hole.y,3,2
    set color white; draw image flag.img,flag.x,flag.y,cell
               
    'supporting lines
    'set color yellow; draw line 0,70,width(primary),70
    'set color yellow; draw line 144,0,144,height(primary)
    'set color yellow; draw line 224,0,224,height(primary)
    'set color yellow; draw line ox,oy,hole.x,hole.y
    'set color yellow; draw line 117,0,117,height(primary)

    '3. Score
    set color white; set caret 10,40; wln "Timer"; wln round(Player.score)
    if round(Player.score) >= 1 then
        Player.score = Player.score - 0.05
    else
        free distance
        hit = false
        Say("TIME OUT..ESC")
        redraw
        play sound oh_no_sound       
        do;wait 1;until keydown(KEY_ESCAPE,true)
        ResetPoints()
        Player.score = 50
        set color black;cls; set color white 'clear screen
    endif         
       
    '----------
    ' Control
    '----------   
    'Left click mouse   
    if mousebutton(0) then
        points[1][0] = mousex()
        points[1][1] = mousey()
       
        'use random number, wind blowing perhaps :-)
        wind = rnd(-10,10)
        p10 = points[1][0]+wind
        p11 = points[1][1]+wind
        drawline = true
    else
        drawline = false
    endif   

    'set how high your golf ball
    set color black_alpha; cls 'clear screen
    if drawline = true or stay then
        set color yellow
        draw line points[0][0],points[0][1],points[1][0],points[1][1]
        draw rect points[1][0] - 8, points[1][1] - 8,16,16 
        Say("ENTER to shoot")
        stay = true
    else
        Say("Drag point from O")       
    endif

    ' 2. ENTER to move ball along the PolyLine path
    if keydown(KEY_RETURN,true) then

        'unpredictable wind ...lol
        if wind<0 then
            cell=0
        else
            cell=1
        endif
       
        Action(3,0,2)
        play sound hit_ball_sound
        hit = not hit 'toggle on/off
        stay = false
    endif   
    if hit then
        points[0]=[ox,oy]
        points[1]=[p10,p11]
        points[2]=[p20,p21]
       
        'points[2] coordinate
        p20 =  p10*2
        'p21 is on a line between (ox,oy) and (hole.x,hole.y)
        'the equation of the line is y = -0.71x + 200.45
        p21 = -0.71*p20 + 200.45       
       
        path = PolyLine(points,0)'0 = opened_path
        distance = (distance + speed)%path.GetLength()
        pos = path.GetPoint(distance, 1) '1=curved
       
        draw ellipse pos[0], pos[1], 2, 2, 1 '1 = filled ellipse
       
        set caret width(primary)/2, height(primary) - 25
        set color white;draw image Player.swing,Player.x,Player.y,2 'stay at the position during the shoot

        'stop the ball and clear the remaining path's distance
        if round(distance) > 0.95*path.GetLength()then
            free distance
            hit = false
            Say("Drag square from O")
        endif
                       
        'collision detection between the ball and the hole
        '1.distance between the center of the ball and the center of the hole
        cbh = sqr(pow(hole.x-pos[0],2)+pow(hole.y-pos[1],2))
        if cbh<(2+3) then
            Say("Hole-in-one,ENTER")
            PlayTune(1)
            free distance
            redraw
            hit = false
           
            'Renew variable values
            hole = [x:rnd(149,219),y:70]        'random x position of hole 
            ox = rnd(50,50+length);oy = 165     'random ox point
            Player.x = ox-25; Player.y = oy - 30'player's position
            ResetPoints()                       'polyline's path
                                               
            'Highscore
            if HS_AddEntry(Player.name, Player.score) then
                HS_Save(hiFilename)
            else
                Say("mmm...")
                redraw
                do;wait 1;until keydown(KEY_ESCAPE,true)
            endif   
            Action(5,0,0)
        endif

    endif

    '-------------------------------
    ' Standy by
    '-------------------------------
    if hit=false then Action(0,0,1)
       
    redraw
    fwait 30
wend

'Ending
Say("I'll miss you !")
redraw
do;wait 1;until keydown(KEY_ESCAPE,true)
Say("Thank You")
redraw
do;wait 1;until keydown(KEY_ESCAPE,true)


'-----------
' FUNCTIONS
'-----------
function Action(type,cell1,cell2)
    set color white
    select type
    case 0 'stand by position
        Player.standby = loadimage("assets/standby.png",2,1)
        timer.Duration = (clock() - timer.Start)/1000
        if round(timer.Duration)%2 = 0 then
            i=cell2
        else
            i=cell1
        endif
        draw image Player.standby, Player.x, Player.y, i
    case 1 'Mario's face animation
        Player.face = loadimage("assets/say.png",3,1)
        draw image Player.face, 20,5,j
        timer.Duration = (clock() - timer.Start)/1000
        if round(timer.Duration)%2 = 0 then
            if j <= 1 then
                j = j+1
            endif
        else
            j = 0
        endif
    case 3 'swing the golf club
        for k = cell1 to cell2
            'set color black
            '   draw rect Player.x,Player.y,width(Player.standby),height(Player.standby),1
            set color white
            Player.swing = loadimage("assets/swing.png",3,1)
            draw image Player.swing, Player.x, Player.y,k
            redraw
            wait 250
        next
        'set color black; draw rect Player.x,Player.y,width(Player.standby),height(Player.standby),1
        redraw
    case 4'title screen
        title = false
        set color white
        set caret width(primary)/2,0

        set justification center
        lines = split(system("type assets\story.txt"), chr(10))
        for k = 0 to sizeof(lines) - 1
            wln lines[k]
        next
        set justification left

        redraw
        PlayTune(1)
        do; wait 1; until keydown(KEY_ESCAPE,true)
    case 5'display wall of fame
        set color black;cls;set color white
        Say("Wall of Fame")
        HS_Load(hiFilename)
        DisplayList()     
        redraw
        PlayTune(1)
        do; wait 1; until keydown(KEY_ESCAPE,true)
    case 6'input name
        set color black;cls;set color white
        Say("Please Identify")
        set caret width(primary)/2-30,height(primary)/2; center "Your name:?  ";
        set caret width(primary)/2+20,height(primary)/2; Player.name = rln(10)       
        PlayTune(1)
        set caret width(primary)/2,height(primary)-20;center "Press ESC to continue"
        redraw
        do; wait 1; until keydown(KEY_ESCAPE,true)
    endsel
endfunc

'Reset draggable path points
function ResetPoints()
    points[0] = [ox,oy]
    points[1] = [ox,oy]
    points[2] = [ox,oy]
endfunc

function Say(message)
    set color green_; draw rect 0,0,width(primary),35,1 '1 = filled rectangle
    set color white; set caret width(primary)/2,15; center message

    'Mario's face
    Action(1,0,2)
    draw line 0,35,width(primary),35
endfunc

function DisplayList()
    entries = HS_GetEntries()
    for i = 0 to sizeof(entries) - 1
        set caret 50, 50+i*16; write entries[i].name
        set caret 200, 50+ i*16; set justification right ;write entries[i].score
        set justification left
    next
    wln
    set caret width(primary)/2,height(primary)-20; center "Press ESC to continue"
endfunc



RE: Tiny Golf - Marcus - 03-25-2024

I think my balls might be possessed by an evil spirit ...


RE: Tiny Golf - 1micha.elok - 03-26-2024

(03-25-2024, 07:09 PM)Marcus Wrote: I think my balls might be possessed by an evil spirit ...

A golf ball possesed by an evil spirit ... lol .... Big Grin

I found some bugs :
  - flag position is not near the hole when restarting a new game. 
 -  drag your mouse from point O while the ball is still flying, then you may see "a ghost ball" sometimes 
    
Fixed bugs will be released by the end of this week (before the Good Friday or before the Easter Sunday)
.... as well as "a crazy idea" of visitors from outerspace (Aliens / UFO) that try to pick you up into their spaceship while you are playing golf  ....mmm.... you can shoot them with the golf ball ( I hope Johnno likes the alien things ).... lol ....

Be patient for the next released : )


RE: Tiny Golf - 1micha.elok - 03-28-2024

TINY GOLF - DAY 4 

           
click the images to zoom in

 What's new ?
1. Something will interrupt you in the middle of the game :
  An alien / UFO will abduct you if the timer is below 25.
  It's weird if the UFO appears too soon or too many times...lol
2. Implement N7 features : json and image manipulation
3. Fixed bug :
  - flag position didn't follow the hole when restarting a new game.
  - you might see "a ghost ball" sometimes, when you dragged your mouse from point O while the ball was still flying   
4. Add some scenes : Disclaimer, Time Out             

 Controls :
 1. LEFT click and drag from O to aim
 2. ENTER to swing the golf club
 3. ESC to continue / quit

 Acknowledgements :
 - Libraries by Marcus :
  * polyline.n7, polyline path
  * sfx.n7, sound effects
  * json.n7, JSON manipulation
  * hiscore.n7, example in N7 by Marcus, original N6 by JSM
  * transform.n7 (collection of functions for image manipulation)
 - Some sound effects and draggable point on polyline By Kevin
  * hit_ball_sound, oh_no_sound are copied from the "Pool" game
  * https://naalaa.com/forum/thread-90-post-493.html#pid493
 - Discussion on text file, thanks to Tomaaz and Marcus
  * https://www.naalaa.com/forum/thread-109.html
 - Sprites :
  * UFO and alien sprites are copied from denaalaafender by Marcus
    https://naalaa.com/forum/thread-30.html
  * Mario https://www.spriters-resource.com/game_boy_gbc/mariogolf/sheet/12294/
  * Flag https://www.cleanpng.com/png-golf-golf-course-flag-pole-green-white-ball-pictur-7951521


Code:
'-----------------------------------
' TINY GOLF - DAY 4
' ==================
' Help Mario to make a hole-in-one
' and achieve The World Record
' of The Tiny Golf
'
' Made with N7_240310
'
' What's new ?
'1. Something will interrupt you in the middle of the game :
'   An alien / UFO will abduct you if the timer is below 25.
'   It's weird if the UFO appears too soon or too many times...lol
'2. Implement N7 features : json and image manipulation
'3. Fixed bug :
'   - flag position didn't follow the hole when restarting a new game.
'   - when you dragged your mouse from point O while the ball was still flying,
'     you might see "a ghost ball" sometimes.
'4. Add some scenes : Disclaimer, Time Out              
'
' Controls :
' 1. LEFT click and drag from O to aim
' 2. ENTER to swing the golf club
' 3. ESC to continue / quit
'
' Acknowledgements :
' - Libraries by Marcus :
'   * polyline.n7, polyline path
'   * sfx.n7, sound effects
'   * json.n7, JSON manipulation
'   * hiscore.n7, example in N7 by Marcus, original N6 by JSM
'   * transform.n7 (collection of functions for image manipulation)
' - Some sound effects and draggable point on polyline By Kevin
'   * hit_ball_sound, oh_no_sound are copied from the "Pool" game
'   * https://naalaa.com/forum/thread-90-post-493.html#pid493
' - Discussion on text file, thanks to Tomaaz and Marcus
'   * https://www.naalaa.com/forum/thread-109.html
' - Sprites :
'   * UFO and alien sprites are copied from denaalaafender by Marcus
'     https://naalaa.com/forum/thread-30.html
'   * Mario https://www.spriters-resource.com/game_boy_gbc/mariogolf/sheet/12294/
'   * Flag https://www.cleanpng.com/png-golf-golf-course-flag-pole-green-white-ball-pictur-7951521
'----------------------------------

'-----------------
' INITIALIZATION
'-----------------
#win32
include "assets/sound_effect.n7"
include "assets/transform.n7"
include "assets/highscore.n7"
include "polyline.n7"
include "json.n7"
set window "TINY GOLF",250,180,false,3
set redraw off
randomize clock()

'color definition
visible black_alpha = [0,0,0,70]
visible black       = [0,0,0]
visible white       = [255,255,255]
visible gray        = [150,150,150]
visible green_      = [0,80,0]
visible green       = [0,255,0,24]
visible yellow      = [200,200,0]

'Golf course
visible ox = 50,oy = 165     'origin point
axy = 360-45                 'angle between x and y-axis
length = 150                 'length of axis 
hole = [x:rnd(149,219),y:70] 'random x position of hole 

'Polygon
grass =
[
    ox,oy,
    length+ox,oy,
    ox+length*cos(rad(axy))+length-80 ,oy+length*sin(rad(axy)),
    ox+length*cos(rad(axy))          ,oy+length*sin(rad(axy))
]

'PolyLine Path
visible points = []
visible p10,p11,p20 = ox; p21=oy
ResetPoints()
path = PolyLine(points,0)'0 = opened path
distance = 0; speed = 5

'Player
visible Player = []
Player.x = ox -25
Player.y = oy -30
Player.standby = loadimage("assets/standby.png",2,1)
Player.face = loadimage("assets/say.png",3,1)
Player.swing = loadimage("assets/swing.png",3,1)
Player.timeout = loadimage("assets/timeout.png")
Player.abductedimg = loadimage("assets/abducted.png")
Player.abducted = false
Player.name = 0
Player.score = 50

'Sound effect (duration, pitch, fadeOut, sampleRate)
hit_ball_sound = CreateNoiseSfx(0.1, 1.05, 0, 14200)
visible oh_no_sound = CreateSineSfx(1.7,600,310,0.215,11600)

'highscore
visible hiFilename = "assets/highscore.txt"

'flag
flag = []
flag.img = loadimage("assets/flag.png",2,1)
flag.x = hole.x-width(flag.img)/2
flag.y = hole.y-height(flag.img) 
cell = 1 '1=left, 0=right
wind = 0

'other sprites : UFO, alien
visible UFO = []
UFO.img = Create(1,JSON_FromFile("assets/ufo.json"),3) 'image grid 4x1
UFO.state = true
UFO.cell = 0
UFO.x = 250
UFO.y = 50

visible alien = []
alien.img = Create(2,JSON_FromFile("assets/alien.json"),2) 'image grid 4x1
alien.state = false
alien.cell = 0
alien.x = UFO.x
alien.y = UFO.y+20

'Other initial values
hit = false
drawline = false
stay = false
visible title = true
visible timer = []; timer.Start = clock()
visible i=0,j=0 'counter
onjourney = false
ending = []; ending[1] = "I'll miss you..."; ending[2] = "Thanks"

'------------
' MAIN LOOP
'------------
while not keydown(KEY_ESCAPE,true)
   
    '----------------------
    '     title screen
    '----------------------
    if title=true then
        Action(7,0,0) 'opening screen
        Action(4,0,0) 'background story
        Action(5,0,0) 'wall of fame
        Action(6,0,0) 'input name
    endif
   
    '----------------------
    '   screen layout
    '----------------------
    '1. golf course
    set color green; draw poly grass,1
    set color white; draw poly grass
    set caret ox,oy;wln "O"
    set color black; draw ellipse hole.x,hole.y,3,2,1
    set color white; draw ellipse hole.x,hole.y,3,2
    set color white; draw image flag.img,flag.x,flag.y,cell
               
    'supporting lines
    'set color yellow; draw line 0,70,width(primary),70
    'set color yellow; draw line 144,0,144,height(primary)
    'set color yellow; draw line 224,0,224,height(primary)
    'set color yellow; draw line ox,oy,hole.x,hole.y
    'set color yellow; draw line 117,0,117,height(primary)

    '3. Score
    set color white; set caret 5,40; write round(Player.score)
    if round(Player.score) >= 1 then
        Player.score = Player.score - 0.05
    else
        timeout()
    endif
   
    '4. Draw other sprites             
    if Player.score <= 25 then AddUFO()
    if alien.state then AddAlien()
                                                              
    '----------
    ' Control
    '----------   
    'Left click mouse   
    if mousebutton(0) and not onjourney and Player.abducted = false then
        points[1][0] = mousex()
        points[1][1] = mousey()
       
        'use random number, wind blowing perhaps :-)
        wind = rnd(-10,10)
        p10 = points[1][0]+wind
        p11 = points[1][1]+wind
        drawline = true
    else
        drawline = false
    endif  

    'set how high your golf ball
    set color black_alpha; cls 'clear screen
    if drawline = true or stay then
        set color yellow
        draw line points[0][0],points[0][1],points[1][0],points[1][1]
        draw rect points[1][0] - 8, points[1][1] - 8,16,16 
        Say("ENTER to shoot")
        stay = true
    else
        Say("Drag point from O")       
    endif

    ' 2. ENTER to move ball along the PolyLine path
    if keydown(KEY_RETURN,true) and Player.abducted=false then

        'unpredictable wind ...lol
        if wind<0 then
            cell=0
        else
            cell=1
        endif
       
        Action(3,0,2)
        play sound hit_ball_sound
        hit = not hit 'toggle on/off
        stay = false
    endif   
    if hit then
        points[0]=[ox,oy]
        points[1]=[p10,p11]
        points[2]=[p20,p21]
       
        'points[2] coordinate
        p20 =  p10*2
        'p21 is on a line between (ox,oy) and (hole.x,hole.y)
        'the equation of the line is y = -0.71x + 200.45
        p21 = -0.71*p20 + 200.45       
       
        path = PolyLine(points,0)'0 = opened_path
        distance = (distance + speed)%path.GetLength()
        pos = path.GetPoint(distance, 1) '1=curved
       
        draw ellipse pos[0], pos[1], 2, 2, 1 '1 = filled ellipse
       
        set caret width(primary)/2, height(primary) - 25
        set color white;draw image Player.swing,Player.x,Player.y,2 'stay at the position during the shoot

        'stop the ball and clear the remaining path's distance
        if round(distance) > 0.95*path.GetLength()then
            free distance
            onjourney = false
            hit = false
            Say("Drag square from O")
        else
            onjourney = true
            Say("Wait for the ball")
        endif
                       
        'collision detection between the ball and the hole
        'cbh = distance between the center of the ball and the center of the hole
        cbh = sqr(pow(hole.x-pos[0],2)+pow(hole.y-pos[1],2))
        if cbh<(2+3) then
            Say("Hole-in-one,ENTER")
            PlayTune(1)
            free distance
            redraw
            hit = false
           
            'Renew variable values
            hole = [x:rnd(149,219),y:70]        'random x position of hole 
            ox = rnd(50,50+length);oy = 165     'random ox point
            Player.x = ox-25; Player.y = oy - 30'player's position
            ResetPoints()                       'polyline's path
            flag.x = hole.x-width(flag.img)/2   'flag position
            flag.y = hole.y-height(flag.img)    'flag position
            onjourney = false                   'ball back to golfer
                                               
            'Highscore
            if HS_AddEntry(Player.name, Player.score) then
                HS_Save(hiFilename)
            else
                Say("ESC to continue")
                redraw
                do;wait 1;until keydown(KEY_ESCAPE,true)
            endif   
            Action(5,0,0)
           
            Player.score = 50 'reset score               
        endif

    endif

    '-------------------------------
    ' Stand by
    '-------------------------------
    if hit=false then Action(0,0,1)
       
    redraw
    fwait 30
wend

'Ending
for i = 1 to 2
    Say(ending[i])
    redraw
    do;wait 1;until keydown(KEY_ESCAPE,true)
next

'-----------
' FUNCTIONS
'-----------
function Action(type,cell1,cell2)
    set color white
    select type
    case 0 'stand by position
        if Player.abducted = false then
            timer.Duration = (clock() - timer.Start)/1000
            if round(timer.Duration)%2 = 0 then
                i=cell2
            else
                i=cell1
            endif
            draw image Player.standby, Player.x, Player.y, i
        else
            draw image Player.abductedimg, Player.x+10, Player.y
        endif
    case 1 'Mario's face animation
        draw image Player.face, 20,5,j
        timer.Duration = (clock() - timer.Start)/1000
        if round(timer.Duration)%2 = 0 then
            if j <= 1 then
                j = j+1
            endif
        else
            j = 0
        endif
    case 3 'swing the golf club
        for k = cell1 to cell2
            'set color black
            '   draw rect Player.x,Player.y,width(Player.standby),height(Player.standby),1
            set color white
            draw image Player.swing, Player.x, Player.y,k
            redraw
            wait 250
        next
        'set color black; draw rect Player.x,Player.y,width(Player.standby),height(Player.standby),1
        redraw
    case 4'title screen
        title = false
        set color black;cls;set color white
        set caret width(primary)/2,0

        set justification center
        lines = split(system("type assets\story.txt"), chr(10))
        for k = 0 to sizeof(lines) - 1
            wln lines[k]
        next
        set justification left

        redraw
        PlayTune(1)
        do; wait 1; until keydown(KEY_ESCAPE,true)
    case 5'display wall of fame
        set color black;cls;set color white
        Say("Wall of Fame")
        HS_Load(hiFilename)
        Display_HiScore()    
        redraw
        PlayTune(1)
        do; wait 1; until keydown(KEY_ESCAPE,true)
    case 6'input name
        set color black;cls;set color white
        Say("Please Identify")
        set caret width(primary)/2-30,height(primary)/2; center "Your name:?  ";
        set caret width(primary)/2+20,height(primary)/2; Player.name = rln(10)       
        PlayTune(2)
        set caret width(primary)/2,height(primary)-20;center "Press ESC to continue"
        redraw
        do; wait 1; until keydown(KEY_ESCAPE,true)
    case 7'opening screen
        set color black;cls
        set color yellow; set caret width(primary)/2,10
        center "Disclaimer : "
        center
        center "This tiny game was made by"
        center "a hobbyist programmer."
        center "It's neither affliated with,"
        center "nor approved by Nintendo."
        center "All trademarks are"
        center "the property of "
        center "their respective owners"
        set color white;
        set caret width(primary)/2,height(primary)-20;center "Press ESC to continue"
        PlayTune(2)
        redraw
        do; wait 1; until keydown(KEY_ESCAPE,true)
    endsel
endfunc

'Reset draggable path points
function ResetPoints()
    points[0] = [ox,oy]
    points[1] = [ox,oy]
    points[2] = [ox,oy]
endfunc

'Say something on the screen
function Say(message)
    set color green_; draw rect 0,0,width(primary),35,1 '1 = filled rectangle
    set color white; set caret width(primary)/2,15; center message

    'Mario's face
    Action(1,0,2)
    draw line 0,35,width(primary),35
endfunc

function AddUFO()
    if UFO.x >=Player.x then
        UFO.x = UFO.x-1
    else
        UFO.x = Player.x
    endif
    if Player.x >=UFO.x and Player.x <=UFO.x+width(UFO.img) then
        UFO.state = false
        alien.state = true
        PlayTune(4)
    endif 
    if UFO.cell <=3 then
        UFO.cell = UFO.cell + 0.5
    else
        UFO.cell = 0
    endif
    set color white;draw image UFO.img,UFO.x,UFO.y,UFO.cell
endfunc

function AddAlien()
    alien.x = Player.x+10
    set color white; draw image alien.img,alien.x,alien.y,alien.cell       
    if alien.cell <=3 then
        alien.cell = alien.cell + 0.5
    else
        alien.cell = 0
    endif
    if alien.y<=Player.y-10 then
        alien.y = alien.y + 1   
    elseif alien.y < = Player.y then
        alien.y = alien.y - 1
        Player.y = Player.y - 1
        Player.abducted = true
        if alien.y <= UFO.y+20 then
            alien.state = false
            alien.y = -50
            Player.y = -50
            timeout()
        endif
    endif
endfunc

function timeout()
    free distance
    hit = false
    set color black;cls; set color white 'clear screen
    if alien.state = false Say("YOU'VE GONE :(")
    if round(Player.score) < 1 Say("TIME OUT..ESC")
    draw image Player.timeout,(width(primary)-width(Player.timeout))/2,40
    redraw
    play sound oh_no_sound       
    do;wait 1;until keydown(KEY_ESCAPE,true)
   
    ResetPoints()
    onjourney = false
    Player.score = 50
    Player.abducted = false
    Player.y = oy-30
    UFO.x = 250
    alien.y = UFO.y + 20
endfunc