revamped sound engine
[fishladder.git] / fishladder.c
index b95248c0d76443f19c2015fe3626f829bd89b2a8..becb812d88b5bb9b48a800ad8846962b2f7509f6 100644 (file)
@@ -1,38 +1,12 @@
 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
 
+//#define VG_CAPTURE_MODE
 #define VG_STEAM
 #define VG_STEAM_APPID 1218140U
 #include "vg/vg.h"
 #include "fishladder_resources.h"
 
-/*
-       Todo for release:
-               Tutorial levels:
-                       1. Transport
-                       2. Split
-                       3. Merge (and explode)
-                       4. Principle 1 (divide colours)
-                       5. Principle 2 (combine colours)
-                       
-               Trainee levels:
-                       Simple maths                    (x3)
-                       Colour ordering                 (x2)
-                       Routing problems                (x2)
-                       
-               Medium levels:
-                       Reverse order
-               
-               New things to program:
-                       UI text element renderer (SDF)                          DONE(sorta)
-                       Particle system thing for ball collision        
-                       Level descriptions / titles                                     HALF
-                       Row Gridlines for I/O                                                   DONE
-                       Play button / Speed controller                          PLAY/PAUSED.. todo: speed, wire connecty
-                       
-                       
-       After release:
-               
-*/
+// #define STEAM_LEADERBOARDS
 
 // CONSTANTS
 // ===========================================================================================================
@@ -728,6 +702,20 @@ static int map_load( const char *str, const char *name )
                                px[3] = 0;
                        }
                }
+               
+               // Level selection area
+               
+               for( int y = 16+2; y < 16+world.h-2; y ++ )
+               {
+                       for( int x = 14; x < 16; x ++ )
+                       {
+                               u8 *px = &info_buffer[((y*64)+x)*4];
+                               px[0] = 0x10;
+                       }
+               }
+               
+               info_buffer[(((16+world.h-3)*64)+world.w+16-1)*4] = 0x30;
+               info_buffer[(((16+world.h-2)*64)+world.w+16-1)*4] = 0x30;
 
                // Random walks.. kinda
                for( int i = 0; i < arrlen(world.io); i ++ )
@@ -1060,6 +1048,12 @@ static int is_simulation_running(void)
        return world.buttons[ k_world_button_sim ].pressed;
 }
 
+static void clear_animation_flags(void)
+{
+       for( int i = 0; i < world.w*world.h; i ++ )
+               world.data[ i ].state &= ~(FLAG_FLIP_FLOP|FLAG_FLIP_ROTATING);
+}
+
 static void simulation_stop(void)
 {
        world.buttons[ k_world_button_sim ].pressed = 0;
@@ -1068,14 +1062,40 @@ static void simulation_stop(void)
        world.num_fishes = 0;
        world.sim_frame = 0;
        world.sim_run = 0;
+       world.frame_lerp = 0.0f;
        
        io_reset();
        
        sfx_system_fadeout( &audio_system_balls_rolling, 44100 );
        
+       clear_animation_flags();
+       
        vg_info( "Stopping simulation!\n" );
 }
 
+static void simulation_start(void)
+{
+       vg_success( "Starting simulation!\n" );
+                               
+       sfx_set_playrnd( &audio_rolls, &audio_system_balls_rolling, 0, 1 );
+       
+       world.num_fishes = 0;
+       world.sim_frame = 0;
+       world.sim_run = 0;
+       
+       world.sim_delta_speed = 2.5f;
+       world.sim_delta_ref = vg_time;
+       world.sim_internal_ref = 0.0f;
+       world.sim_internal_time = 0.0f;
+       world.pause_offset_target = 0.0f;
+       
+       world.sim_target = 0;
+       
+       clear_animation_flags();
+       
+       io_reset();
+}
+
 static int world_check_pos_ok( v2i co )
 {
        return (co[0] < 2 || co[0] >= world.w-2 || co[1] < 2 || co[1] >= world.h-2)? 0: 1;
@@ -1247,7 +1267,7 @@ void vg_update(void)
                        
                        if( vg_get_button_up("secondary") && world.id_drag_from == world.selected )
                        {
-                               u32 link_id = local_x > 0.5f? 1: 0;
+                               u32 link_id = cell_ptr->links[ 0 ]? 0: 1;
                                
                                // break existing connection off
                                if( cell_ptr->links[ link_id ] )
@@ -1265,7 +1285,7 @@ void vg_update(void)
                                world.id_drag_from = 0;
                        }
                        
-                       if( world.id_drag_from && (cell_ptr->state & FLAG_CANAL) && (cell_ptr->config == k_cell_type_split) )
+                       else if( world.id_drag_from && (cell_ptr->state & FLAG_CANAL) && (cell_ptr->config == k_cell_type_split) )
                        {
                                world.drag_to_co[0] = (float)world.tile_x + (local_x > 0.5f? 0.75f: 0.25f);
                                world.drag_to_co[1] = (float)world.tile_y + 0.25f;
@@ -1337,6 +1357,9 @@ void vg_update(void)
                
                world.sim_target = (int)floorf(world.sim_internal_time);
                
+               int success_this_frame = 0;
+               int failure_this_frame = 0;
+               
                while( world.sim_frame < world.sim_target )
                {
                        sfx_set_playrnd( &audio_random, &audio_system_balls_switching, 0, 8 );
@@ -1384,7 +1407,16 @@ void vg_update(void)
                                                        {
                                                                struct terminal_run *run = &term->runs[ world.sim_run ];
                                                                if( run->recv_count < vg_list_size( run->recieved ) )
+                                                               {
+                                                                       if( fish->payload == run->conditions[ run->recv_count ] )
+                                                                               success_this_frame = 1;
+                                                                       else
+                                                                               failure_this_frame = 1;
+                                                               
                                                                        run->recieved[ run->recv_count ++ ] = fish->payload;
+                                                               }
+                                                               else
+                                                                       failure_this_frame = 1;
                                                                
                                                                break;
                                                        }
@@ -1730,6 +1762,21 @@ void vg_update(void)
                        world.sim_frame ++;
                }
                
+               // Sounds
+               if( failure_this_frame )
+               {
+                       sfx_set_play( &audio_tones, &audio_system_balls_extra, 0 );
+               }
+               else if( success_this_frame )
+               {
+                       static int succes_counter = 0;
+                       
+                       sfx_set_play( &audio_tones, &audio_system_balls_extra, 1+(succes_counter++) );
+                       
+                       if( succes_counter == 7 )
+                               succes_counter = 0;
+               }
+               
                // Position update
                // =====================================================================================================
                
@@ -1888,30 +1935,6 @@ static void draw_numbers( v3f coord, int number )
        }
 }*/
 
-static void simulation_start(void)
-{
-       vg_success( "Starting simulation!\n" );
-                               
-       sfx_set_playrnd( &audio_rolls, &audio_system_balls_rolling, 0, 1 );
-       
-       world.num_fishes = 0;
-       world.sim_frame = 0;
-       world.sim_run = 0;
-       
-       world.sim_delta_speed = 2.5f;
-       world.sim_delta_ref = vg_time;
-       world.sim_internal_ref = 0.0f;
-       world.sim_internal_time = 0.0f;
-       world.pause_offset_target = 0.0f;
-       
-       world.sim_target = 0;
-       
-       for( int i = 0; i < world.w*world.h; i ++ )
-               world.data[ i ].state &= ~FLAG_FLIP_FLOP;
-       
-       io_reset();
-}
-
 static void wbutton_run( enum e_world_button btn_name )
 {
        static v3f button_colours[] = {
@@ -1924,6 +1947,7 @@ static void wbutton_run( enum e_world_button btn_name )
        struct cell_button *btn = &world.buttons[btn_name];
        
        // Interaction
+       int tex_offset = 0;
        
        int is_hovering = (world.tile_x == world.w-1 && world.tile_y == world.h-btn_name-2)?1:0;        
        if( vg_get_button_up( "primary" ) && is_hovering )
@@ -2002,6 +2026,13 @@ static void wbutton_run( enum e_world_button btn_name )
        btn->light = vg_lerpf( btn->light, btn->light_target, vg_time_delta*26.0f );
        
        // Draw
+       if( btn_name == k_world_button_sim && world.buttons[ k_world_button_sim ].pressed )
+       {
+               if( world.buttons[ k_world_button_pause ].pressed )
+                       tex_offset = 3;
+               else
+                       tex_offset = 2;
+       }
        
        v4f final_colour;
        v3_copy( button_colours[ btn_name ], final_colour );
@@ -2010,7 +2041,7 @@ static void wbutton_run( enum e_world_button btn_name )
        glUniform4f( SHADER_UNIFORM( shader_buttons, "uOffset" ), 
                world.w-1, 
                world.h-btn_name-2, 
-               (float)btn_name
+               (float)(btn_name+tex_offset)
                3.0f 
        );
        glUniform4fv( SHADER_UNIFORM( shader_buttons, "uColour" ), 1, final_colour );
@@ -2035,6 +2066,9 @@ void vg_render(void)
        int const empty_start = circle_base+32;
        int const empty_count = circle_base+32*2;
        
+       if( !world.initialzed )
+               return;
+       
        // BACKGROUND
        // ========================================================================================================
        use_mesh( &world.shapes );
@@ -2532,6 +2566,7 @@ ui_data;
 
 void vg_ui(void)
 {
+       /*
        // UI memory
        static int pack_selection = 0;
        static struct pack_info
@@ -2573,7 +2608,7 @@ void vg_ui(void)
                gui_capture_mouse( 9999 );
                gui_fill_rect( ui_global_ctx.cursor, 0xff5a4e4d );
                
-               gui_text( "ASSIGNMENTS", 8, 0 );
+               gui_text( "ASSIGNMENTS", 32, 0 );
                
                ui_global_ctx.cursor[1] += 30;
                ui_global_ctx.cursor[3] = 25;
@@ -2594,7 +2629,7 @@ void vg_ui(void)
                                        pack_selection = i;
                                
                                ui_global_ctx.cursor[1] += 2;
-                               gui_text( pack_is_unlocked? pack_infos[i].name: "???", 4, 0 );
+                               gui_text( pack_is_unlocked? pack_infos[i].name: "???", 24, 0 );
                                gui_end_right();
                                
                                gui_reset_colours();
@@ -2666,18 +2701,18 @@ void vg_ui(void)
                                                }
                                                
                                                ui_global_ctx.override_colour = 0xffffffff;
-                                               gui_text( lvl_info->title, 6, 0 );
+                                               gui_text( lvl_info->title, 24, 0 );
                                                ui_global_ctx.cursor[1] += 18;
-                                               gui_text( lvl_info->completed_score>0? "passed": "incomplete", 4, 0 );
+                                               gui_text( lvl_info->completed_score>0? "passed": "incomplete", 24, 0 );
                                        }
                                        else
                                        {
                                                gui_button( 2 + i );
                                                
                                                ui_global_ctx.override_colour = 0xff786f6f;
-                                               gui_text( "???", 6, 0 );
+                                               gui_text( "???", 24, 0 );
                                                ui_global_ctx.cursor[1] += 18;
-                                               gui_text( "locked", 4, 0 );
+                                               gui_text( "locked", 24, 0 );
                                        }
                                        
                                        gui_end_down();
@@ -2707,7 +2742,7 @@ void vg_ui(void)
                        
                        gui_fill_rect( ui_global_ctx.cursor, 0xff5a4e4d );
                        ui_global_ctx.cursor[1] += 4;
-                       gui_text( ui_data.level_selected->title, 6, 0 );
+                       gui_text( ui_data.level_selected->title, 24, 0 );
                        
                        ui_global_ctx.cursor[1] += 30;
                        ui_rect_pad( ui_global_ctx.cursor, 8 );
@@ -2719,11 +2754,11 @@ void vg_ui(void)
                        }
                        gui_end_down();
                        
-                       ui_text_use_paragraph( &ui_global_ctx );
+                       //ui_text_use_paragraph( &ui_global_ctx );
                        ui_global_ctx.cursor[1] += 2;
                        
-                       gui_text( ui_data.level_selected->description, 5, 0 );
-                       ui_text_use_title( &ui_global_ctx );
+                       gui_text( ui_data.level_selected->description, 16, 0 );
+                       //ui_text_use_title( &ui_global_ctx );
                        
                        // Buttons at the bottom
                        ui_global_ctx.cursor[3] = 25;
@@ -2736,7 +2771,7 @@ void vg_ui(void)
                        {
                                ui_data.level_selected = NULL;
                        }
-                       gui_text( "BACK", 6, k_text_alignment_center );
+                       gui_text( "BACK", 24, k_text_alignment_center );
                        gui_end();
                        
                        gui_align_right();
@@ -2750,7 +2785,7 @@ void vg_ui(void)
                                
                                ui_global_ctx.override_colour = 0xff888888;
                                
-                               gui_text( "RESTORE SOLUTION", 6, k_text_alignment_center );
+                               gui_text( "RESTORE SOLUTION", 24, k_text_alignment_center );
                                gui_end_right();
                                ui_global_ctx.override_colour = 0xffffffff;
                        }
@@ -2770,7 +2805,7 @@ void vg_ui(void)
                                                ui_data.leaderboard_show = 0;
                                        }
                                }
-                               gui_text( "PLAY", 6, k_text_alignment_center );
+                               gui_text( "PLAY", 24, k_text_alignment_center );
                                gui_end();
                        }
                        
@@ -2788,7 +2823,7 @@ void vg_ui(void)
                        gui_new_node();
                        {
                                gui_fill_rect( ui_global_ctx.cursor, 0xff5a4e4d );
-                               gui_text( "FRIEND LEADERBOARD", 6, 0 );
+                               gui_text( "FRIEND LEADERBOARD", 24, 0 );
                        }
                        gui_end_down();
                        
@@ -2809,7 +2844,7 @@ void vg_ui(void)
                                                
                                                // 1,2,3 ...
                                                static const char *places[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
-                                               gui_text( places[i], 7, 0 );
+                                               gui_text( places[i], 24, 0 );
                                                ui_global_ctx.cursor[0] += 32;
                                                
                                                struct leaderboard_player *player = &ui_data.leaderboard_players[i];
@@ -2825,12 +2860,12 @@ void vg_ui(void)
                                                gui_end_right();
                                                
                                                // Players name
-                                               gui_text( player->player_name, 7, 0 );
+                                               gui_text( player->player_name, 24, 0 );
                                                
                                                ui_global_ctx.cursor[2] = 50;
                                                gui_align_right();
                                                
-                                               gui_text( player->score_text, 7, k_text_alignment_right );
+                                               gui_text( player->score_text, 24, k_text_alignment_right );
                                        }
                                        gui_end_down();
                                        
@@ -2840,10 +2875,12 @@ void vg_ui(void)
                        gui_end();
                }
        }
+       */
 }
 
 void leaderboard_dispatch_score(void)
 {
+#if STEAM_LEADERBOARDS
        sw_upload_leaderboard_score( 
                ui_data.upload_request.level->steam_leaderboard, 
                k_ELeaderboardUploadScoreMethodKeepBest,
@@ -2855,10 +2892,12 @@ void leaderboard_dispatch_score(void)
        ui_data.upload_request.is_waiting = 0;
        
        vg_success( "Dispatched leaderboard score\n" );
+#endif
 }
 
 void leaderboard_found( LeaderboardFindResult_t *pCallback )
 {
+#ifdef STEAM_LEADERBOARDS
        if( !pCallback->m_bLeaderboardFound )
        {
                vg_error( "Leaderboard could not be found\n" );
@@ -2888,10 +2927,12 @@ void leaderboard_found( LeaderboardFindResult_t *pCallback )
                        }
                }
        }
+#endif
 }
 
 void leaderboard_downloaded( LeaderboardScoresDownloaded_t *pCallback )
 {
+#ifdef STEAM_LEADERBOARDS
        // Update UI if this leaderboard matches what we currently have in view
        if( ui_data.level_selected->steam_leaderboard == pCallback->m_hSteamLeaderboard )
        {
@@ -2926,10 +2967,12 @@ void leaderboard_downloaded( LeaderboardScoresDownloaded_t *pCallback )
                        ui_data.leaderboard_show = 0;
        }
        else vg_warn( "Downloaded leaderboard does not match requested!\n" );
+#endif
 }
 
 void leaderboard_set_score( struct cmp_level *cmp_level, u32 score )
 {
+#ifdef STEAM_LEADERBOARDS
        if( ui_data.upload_request.is_waiting )
                vg_warn( "You are uploading leaderboard entries too quickly!\n" );
                
@@ -2942,6 +2985,7 @@ void leaderboard_set_score( struct cmp_level *cmp_level, u32 score )
                leaderboard_dispatch_score();
        else
                sw_find_leaderboard( cmp_level->map_name );
+#endif
 }
 
 // CONSOLE COMMANDS
@@ -3065,8 +3109,10 @@ static int console_changelevel( int argc, char const *argv[] )
 void vg_start(void)
 {
        // Steamworks callbacks
+       #ifdef STEAM_LEADERBOARDS
        sw_leaderboard_found = &leaderboard_found;
        sw_leaderboard_downloaded = &leaderboard_downloaded;
+       #endif
 
        vg_function_push( (struct vg_cmd){
                .name = "_map_write",