lock levels packs if first is not unlocked
[fishladder.git] / fishladder.c
index 71b714b53a731aa025dab5586f55f728ed89aed4..412182cd21619e4821865ac1733290d1b3f5be71 100644 (file)
@@ -27,7 +27,7 @@
                        Particle system thing for ball collision        
                        Level descriptions / titles                                     HALF
                        Row Gridlines for I/O                                                   DONE
-                       Play button / Speed controller                          ( play buttern, pause, speed control, step button )
+                       Play button / Speed controller                          PLAY/PAUSED.. todo: speed, wire connecty
                        
                        
        After release:
@@ -107,27 +107,29 @@ static struct cell_description
        
        int is_special;
        int is_linear;
+       
+       v2f trigger_pos;
 }
 cell_descriptions[] =
 {
        // 0-3
        {},
-       { .start = {  1,  0 }, .end = { -1,  0 } },
-       { .start = {  0,  1 }, .end = {  0, -1 } },
-       { .start = {  0,  1 }, .end = {  1,  0 } },
+       { .start = {  1,  0 }, .end = { -1,  0 }, .trigger_pos = { 0.5f, 0.25f } },
+       { .start = {  0,  1 }, .end = {  0, -1 }, .trigger_pos = { 0.25f, 0.5f } },
+       { .start = {  0,  1 }, .end = {  1,  0 }, .trigger_pos = { 0.25f, 0.25f } },
        // 4-7
-       { .start = { -1,  0 }, .end = {  1,  0 } },
-       { .start = { -1,  0 }, .end = {  1,  0 }, .is_linear = 1 },
-       { .start = {  0,  1 }, .end = { -1,  0 } },
+       { .start = { -1,  0 }, .end = {  1,  0 }, .trigger_pos = { 0.5f, 0.25f } },
+       { .start = { -1,  0 }, .end = {  1,  0 }, .trigger_pos = { 0.5f, 0.25f }, .is_linear = 1 },
+       { .start = {  0,  1 }, .end = { -1,  0 }, .trigger_pos = { 0.5f, 0.25f } },
        { .start = {  0,  1 }, .is_special = 1 },
        // 8-11
-       { .start = {  0, -1 }, .end = {  0,  1 } },
-       { .start = {  1,  0 }, .end = {  0, -1 } },
-       { .start = {  0,  1 }, .end = {  0, -1 }, .is_linear = 1 },
+       { .start = {  0, -1 }, .end = {  0,  1 }, .trigger_pos = { 0.25f, 0.5f } },
+       { .start = {  1,  0 }, .end = {  0, -1 }, .trigger_pos = { 0.25f, 0.75f } },
+       { .start = {  0,  1 }, .end = {  0, -1 }, .trigger_pos = { 0.25f, 0.5f }, .is_linear = 1 },
        { },
        // 12-15
-       { .start = { -1,  0 }, .end = {  0, -1 } },
-       { .end = { 0, -1 }, .is_special = 1 },
+       { .start = { -1,  0 }, .end = {  0, -1 }, .trigger_pos = { 0.75f, 0.75f } },
+       { .end = { 0, -1 }, .is_special = 1, .trigger_pos = { 0.5f, 0.75f } },
        { },
        { }
 };
@@ -176,6 +178,7 @@ struct world
 
        int sim_frame, sim_target;
        float sim_internal_time,                // current tick-time 
+               sim_internal_delta,                     // time delta
                sim_internal_ref,                               // Reference point of internal time
                sim_delta_ref,                          // Reference point of vg_time when we started at current sim_speed
                sim_delta_speed,                                // Rate to apply time delta
@@ -742,6 +745,9 @@ static int map_load( const char *str, const char *name )
                        turtle_dir[1] = pcell(term->pos)->state & FLAG_INPUT? 1: -1;
                        original_y = turtle_dir[1];
                        
+                       info_buffer[((turtle[1]*64)+turtle[0])*4] = 0;  
+                       v2i_add( turtle_dir, turtle, turtle );
+                       
                        for( int i = 0; i < 100; i ++ )
                        {
                                info_buffer[((turtle[1]*64)+turtle[0])*4] = 0;
@@ -1188,7 +1194,7 @@ void vg_update(void)
        if( !is_simulation_running() && !gui_want_mouse() )
        {
                v2_copy( vg_mouse_ws, world.drag_to_co );
-       
+               
                if( cell_interactive( (v2i){ world.tile_x, world.tile_y } ))
                {
                        world.selected = world.tile_y * world.w + world.tile_x;
@@ -1223,16 +1229,38 @@ void vg_update(void)
                                                                                (v2i){ world.tile_x +2, world.tile_y +2 }, 1 );
                        }
                        
-                       if( vg_get_button_down("secondary") && !(cell_ptr->config == k_cell_type_split) )
+                       if( vg_get_button_down("secondary") && (cell_ptr->state & FLAG_CANAL) && !(cell_ptr->config == k_cell_type_split) )
                        {
                                world.id_drag_from = world.selected;
-                               world.drag_from_co[0] = world.tile_x + 0.5f;
-                               world.drag_from_co[1] = world.tile_y + 0.5f;
+                       
+                               struct cell_description *desc = &cell_descriptions[ world.data[world.id_drag_from].config ];
+                               v2_add( desc->trigger_pos, (v2f){ world.tile_x, world.tile_y }, world.drag_from_co );
                        }
                        
-                       if( world.id_drag_from && (cell_ptr->config == k_cell_type_split) )
+                       float local_x = vg_mouse_ws[0] - (float)world.tile_x;
+                       
+                       if( vg_get_button_up("secondary") && world.id_drag_from == world.selected )
+                       {
+                               u32 link_id = local_x > 0.5f? 1: 0;
+                               
+                               // break existing connection off
+                               if( cell_ptr->links[ link_id ] )
+                               {
+                                       struct cell *current_connection = &world.data[ cell_ptr->links[ link_id ]];
+                                       
+                                       if( !current_connection->links[ link_id ^ 0x1 ] )
+                                               current_connection->state &= ~FLAG_TARGETED;
+                                       
+                                       current_connection->links[ link_id ] = 0;
+                                       cell_ptr->links[ link_id ] = 0;
+                               }
+                               
+                               cell_ptr->state &= ~FLAG_IS_TRIGGER;
+                               world.id_drag_from = 0;
+                       }
+                       
+                       if( world.id_drag_from && (cell_ptr->state & FLAG_CANAL) && (cell_ptr->config == k_cell_type_split) )
                        {
-                               float local_x = vg_mouse_ws[0] - (float)world.tile_x;
                                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;
 
@@ -1293,20 +1321,19 @@ void vg_update(void)
        // ========================================================================================================
        if( is_simulation_running() )
        {       
+               float old_time = world.sim_internal_time;
+       
                if( !world.buttons[ k_world_button_pause ].pressed )
-               {
                        world.sim_internal_time = world.sim_internal_ref + (vg_time-world.sim_delta_ref) * world.sim_delta_speed;
-               }
                else
-               {
                        world.sim_internal_time = vg_lerpf( world.sim_internal_time, world.sim_internal_ref + world.pause_offset_target, vg_time_delta*15.0f );
-               }
+               world.sim_internal_delta = world.sim_internal_time-old_time;
                
                world.sim_target = (int)floorf(world.sim_internal_time);
                
                while( world.sim_frame < world.sim_target )
                {
-                       sfx_set_playrnd( &audio_random, &audio_system_balls_switching, 0, 9 );
+                       sfx_set_playrnd( &audio_random, &audio_system_balls_switching, 0, 8 );
 
                        // Update splitter deltas
                        for( int i = 0; i < world.h*world.w; i ++ )
@@ -1358,6 +1385,7 @@ void vg_update(void)
                                                }
                                                
                                                fish->state = k_fish_state_dead;
+                                               fish->death_time = -1000.0f;
                                                continue;
                                        }
                                        
@@ -1400,7 +1428,10 @@ void vg_update(void)
                                                        if( cell_next->config == k_cell_type_merge )
                                                        {
                                                                if( fish->dir[0] == 0 )
+                                                               {
                                                                        fish->state = k_fish_state_dead;
+                                                                       fish->death_time = world.sim_internal_time;
+                                                               }
                                                                else
                                                                        fish->flow_reversed = 0;
                                                        }
@@ -1416,7 +1447,10 @@ void vg_update(void)
                                                                                fish->flow_reversed = 0;
                                                                        }
                                                                        else
+                                                                       {
                                                                                fish->state = k_fish_state_dead;
+                                                                               fish->death_time = world.sim_internal_time;
+                                                                       }
                                                                }
                                                                else
                                                                        fish->flow_reversed = ( fish->dir[0] != -desc->start[0] || 
@@ -1424,7 +1458,15 @@ void vg_update(void)
                                                        }
                                                }
                                                else
-                                                       fish->state = world_check_pos_ok( fish->pos )? k_fish_state_bg: k_fish_state_dead;
+                                               {
+                                                       if( world_check_pos_ok( fish->pos ) )
+                                                               fish->state = k_fish_state_bg;
+                                                       else
+                                                       {
+                                                               fish->state = k_fish_state_dead;
+                                                               fish->death_time = world.sim_internal_time;     
+                                                       }
+                                               }
                                        }
                                        
                                        //v2i_add( fish->pos, fish->dir, fish->pos );
@@ -1434,7 +1476,10 @@ void vg_update(void)
                                        v2i_add( fish->pos, fish->dir, fish->pos );
                                        
                                        if( !world_check_pos_ok( fish->pos ) )
+                                       {
                                                fish->state = k_fish_state_dead;
+                                               fish->death_time = -1000.0f;
+                                       }
                                        else
                                        {
                                                struct cell *cell_entry = pcell( fish->pos );
@@ -1539,7 +1584,7 @@ void vg_update(void)
                                                                sw_set_achievement( "BANG" );
                                                        
                                                                // Shatter death (+0.5s)
-                                                               float death_time = collide_this_frame? 0.0f: 0.5f;
+                                                               float death_time = world.sim_internal_time + ( collide_this_frame? 0.0f: 0.5f );
                                                                
                                                                fi->state = k_fish_state_soon_dead;
                                                                fj->state = k_fish_state_soon_dead;
@@ -1692,7 +1737,7 @@ void vg_update(void)
                        if( fish->state == k_fish_state_dead )
                                continue;
                        
-                       if( fish->state == k_fish_state_soon_dead && (world.frame_lerp > fish->death_time) )
+                       if( fish->state == k_fish_state_soon_dead && (world.sim_internal_time > fish->death_time) )
                                continue; // Todo: particle thing?
                                
                        struct cell *cell = pcell(fish->pos);
@@ -1758,6 +1803,9 @@ void vg_update(void)
                                fish->physics_co[0] = origin[0] + (float)fish->dir[0]*t;
                                fish->physics_co[1] = origin[1] + (float)fish->dir[1]*t;
                        }
+                       
+                       v2_sub( fish->physics_co, fish->physics_v, fish->physics_v );
+                       v2_divs( fish->physics_v, world.sim_internal_delta, fish->physics_v );
                }
        }
 }
@@ -1848,6 +1896,7 @@ static void simulation_start(void)
        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;
@@ -1860,6 +1909,13 @@ static void simulation_start(void)
 
 static void wbutton_run( enum e_world_button btn_name )
 {
+       static v3f button_colours[] = {
+               {0.204f, 0.345f, 0.553f},
+               {0.204f, 0.345f, 0.553f},
+               {0.741f, 0.513f, 0.078f},
+               {1.0f, 0.0f, 0.0f}
+       };
+
        struct cell_button *btn = &world.buttons[btn_name];
        
        // Interaction
@@ -1876,9 +1932,11 @@ static void wbutton_run( enum e_world_button btn_name )
                                {
                                        btn->pressed = 1;
                                        simulation_start();
+                                       
+                                       world.pause_offset_target = 0.5f;
                                }
-                               
-                               world.pause_offset_target += 1.0f;
+                               else
+                                       world.pause_offset_target += 1.0f;
                        }
                        else
                        {
@@ -1905,6 +1963,12 @@ static void wbutton_run( enum e_world_button btn_name )
                        else
                                world.pause_offset_target = 0.0f;
                }
+               else
+               {
+                       btn->pressed ^= 0x1;
+               }
+               
+               sfx_set_play( &audio_clicks, &audio_system_ui, btn->pressed?1:0 );
        }
        
        // Drawing
@@ -1932,13 +1996,19 @@ 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
+       
+       v4f final_colour;
+       v3_copy( button_colours[ btn_name ], final_colour );
+       final_colour[3] = btn->light;
+       
        glUniform4f( SHADER_UNIFORM( shader_buttons, "uOffset" ), 
                world.w-1, 
                world.h-btn_name-2, 
                (float)btn_name, 
                3.0f 
        );
-       glUniform4f( SHADER_UNIFORM( shader_buttons, "uColour" ), 0.204f, 0.345f, 0.553f, btn->light );
+       glUniform4fv( SHADER_UNIFORM( shader_buttons, "uColour" ), 1, final_colour );
        
        draw_mesh( 0, 2 );
 }
@@ -1954,6 +2024,11 @@ void vg_render(void)
        v4f const colour_default = {1.0f, 1.0f, 1.0f, 1.0f};
        v4f const colour_selected = {0.90f, 0.92f, 1.0f, 1.0f};
 
+       int const circle_base = 4;
+       int const filled_start = circle_base+0;
+       int const filled_count = circle_base+32;
+       int const empty_start = circle_base+32;
+       int const empty_count = circle_base+32*2;
        
        // BACKGROUND
        // ========================================================================================================
@@ -2013,18 +2088,34 @@ void vg_render(void)
                for( int i = 0; i < world.num_fishes; i ++ )
                {
                        struct fish *fish = &world.fishes[i];
+                       v3f render_pos;
+                       render_pos[2] = 1.0f;
                        
-                       if( fish->state == k_fish_state_dead || fish->state == k_fish_state_bg )
+                       if( fish->state == k_fish_state_dead || fish->state == k_fish_state_soon_dead )
+                       {
+                               float death_anim_time = world.sim_internal_time - fish->death_time;
+                               
+                               // Death animation
+                               if( death_anim_time > 0.0f && death_anim_time < 1.0f )
+                               {
+                                       float amt = 1.0f-death_anim_time*death_anim_time;
+                               
+                                       v2_muladds( fish->physics_co, fish->physics_v, -1.0f * world.sim_internal_delta * amt, fish->physics_co );
+                                       render_pos[2] = amt;
+                               }
+                               else if( world.sim_internal_time > fish->death_time )
+                                       continue;
+                       }
+                       else if( fish->state == k_fish_state_bg )
                                continue;
                        
-                       if( fish->state == k_fish_state_soon_dead && (world.frame_lerp > fish->death_time) )
-                               continue;
+                       v2_copy( fish->physics_co, render_pos );
                        
                        v4f dot_colour = { 0.0f, 0.0f, 0.0f, 1.0f };
                        colour_code_v3( fish->payload, dot_colour );
                        
                        glUniform3fv( SHADER_UNIFORM( shader_ball, "uColour" ), 1, dot_colour );
-                       glUniform2fv( SHADER_UNIFORM( shader_ball, "uOffset" ), 1, fish->physics_co );
+                       glUniform3fv( SHADER_UNIFORM( shader_ball, "uOffset" ), 1, render_pos );
                        glUniform2f( SHADER_UNIFORM( shader_ball, "uTexOffset" ), (float)i * 1.2334, (float)i * -0.3579f );
                        draw_mesh( 0, 2 );
                }
@@ -2121,6 +2212,7 @@ void vg_render(void)
        
        wbutton_run( k_world_button_sim );
        wbutton_run( k_world_button_pause );
+       //wbutton_run( k_world_button_wire_mode );
        
        // WIRES
        // ========================================================================================================
@@ -2133,7 +2225,7 @@ void vg_render(void)
        glUniform4f( SHADER_UNIFORM( shader_wire, "uColour" ), 0.2f, 0.2f, 0.2f, 1.0f );
        
        if( world.id_drag_from )
-       {
+       {               
                glUniform1f( SHADER_UNIFORM( shader_wire, "uCurve" ), 0.4f );
                glUniform3f( SHADER_UNIFORM( shader_wire, "uStart" ), world.drag_from_co[0], world.drag_from_co[1], 0.06f );
                glUniform3f( SHADER_UNIFORM( shader_wire, "uEnd" ), world.drag_to_co[0], world.drag_to_co[1], 0.06f );
@@ -2154,6 +2246,8 @@ void vg_render(void)
                        {
                                if( cell->state & FLAG_IS_TRIGGER )
                                {
+                                       struct cell_description *desc = &cell_descriptions[ cell->config ];
+                               
                                        int trigger_id = cell->links[0]?0:1;
                                        
                                        int x2 = cell->links[trigger_id] % world.w;
@@ -2165,8 +2259,10 @@ void vg_render(void)
                                        startpoint[0] = (float)x2 + (trigger_id? 0.75f: 0.25f);
                                        startpoint[1] = (float)y2 + 0.25f;
                                        
-                                       endpoint[0] = x+0.5f;
-                                       endpoint[1] = y+0.5f;
+                                       endpoint[0] = x;
+                                       endpoint[1] = y;
+                                       
+                                       v2_add( desc->trigger_pos, endpoint, endpoint );
                                        
                                        glUniform1f( SHADER_UNIFORM( shader_wire, "uCurve" ), cell->state & FLAG_TRIGGERED? rp_x2 * 0.4f: 0.4f );
                                        glUniform3f( SHADER_UNIFORM( shader_wire, "uStart" ), startpoint[0], startpoint[1], 0.04f );
@@ -2183,12 +2279,6 @@ void vg_render(void)
        SHADER_USE( shader_tile_colour );
        glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
        use_mesh( &world.shapes );
-
-       int const circle_base = 4;
-       int const filled_start = circle_base+0;
-       int const filled_count = circle_base+32;
-       int const empty_start = circle_base+32;
-       int const empty_count = circle_base+32*2;
        
        glEnable(GL_BLEND);
        
@@ -2207,9 +2297,35 @@ void vg_render(void)
                                                (arr_base + (float)term->pos[1] + (float)(term->run_count-1)*0.2f) - run_offset:
                                                (float)term->pos[1] + arr_base + run_offset;
                        
-                       if( k & 0x1 )
+                       v4f bar_colour;
+                       int bar_draw = 0;
+                       
+                       if( is_simulation_running() )
+                       {
+                               if( k == world.sim_run )
+                               {
+                                       float a = fabsf(sinf( vg_time * 2.0f )) * 0.075f + 0.075f;
+                                       
+                                       v4_copy( (v4f){ 1.0f, 1.0f, 1.0f, a }, bar_colour );
+                               }
+                               else
+                                       v4_copy( (v4f){ 0.0f, 0.0f, 0.0f, 0.13f }, bar_colour );
+                               
+                               bar_draw = 1;
+                       }
+                       else if( 1 || k & 0x1 )
+                       {
+                               if( k & 0x1 )
+                                       v4_copy( (v4f){ 1.0f, 1.0f, 1.0f, 0.07f }, bar_colour );
+                               else
+                                       v4_copy( (v4f){ 0.0f, 0.0f, 0.0f, 0.13f }, bar_colour );                        
+                                                       
+                               bar_draw = 1;
+                       }
+                       
+                       if( bar_draw )
                        {
-                               glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1.0f, 1.0f, 1.0f, 0.1f );
+                               glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, bar_colour );
                                glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)term->pos[0], y_position - 0.1f, 1.0f );
                                draw_mesh( 2, 2 );
                        }
@@ -2384,14 +2500,16 @@ void vg_ui(void)
                        
                        for( int i = 0; i < 3; i ++ )
                        {
-                               if( i == pack_selection )
+                               int pack_is_unlocked = pack_infos[i].levels[0].unlocked;
+                       
+                               if( i == pack_selection || !pack_is_unlocked )
                                        gui_override_colours( &flcol_list_locked );
-
-                               if( gui_button( 2000 + i ) == k_button_click )
+                               
+                               if( gui_button( 2000 + i ) == k_button_click && pack_is_unlocked )
                                        pack_selection = i;
                                
                                ui_global_ctx.cursor[1] += 2;
-                               gui_text( pack_infos[i].name, 4, 0 );
+                               gui_text( pack_is_unlocked? pack_infos[i].name: "", 4, 0 );
                                gui_end_right();
                                
                                gui_reset_colours();