emit test, wire fixes
[fishladder.git] / fishladder.c
index 210797b5c349a80eed80d0e14e03f1bcf51a46a3..74f972643492666caabd88500d62892708a1f882 100644 (file)
@@ -79,6 +79,7 @@ enum e_game_state
 #define FLAG_INPUT             0x10
 #define FLAG_OUTPUT            0x20
 #define FLAG_WALL              0x40
+#define FLAG_EMITTER           0x80
 
 #define FLAG_FLIP_FLOP         0x100
 #define FLAG_TRIGGERED         0x200
@@ -213,7 +214,7 @@ static struct world
                u16 state;
                u16 links[2];
                u8 config;
-               u8 pad0;
+               char cc;
        }
        *data;
 #pragma pack(pop)
@@ -325,6 +326,7 @@ static void level_selection_buttons(void);
 static void map_free(void);
 static void io_reset(void);
 static struct cell *pcell( v2i pos );
+static void lcell( int id, v2i pos );
 static void map_reclassify( v2i start, v2i end, int update_texbuffer );
 static u32 gen_text_buffer( const char *str, struct sdf_font *font, v2f origin, float size, u32 start );
 static void gen_level_text( struct cmp_level *pLevel );
@@ -345,7 +347,7 @@ static void clear_animation_flags(void);
 // -------------
 static void simulation_stop(void);
 static void simulation_start(void);
-static int world_check_pos_ok( v2i co );
+static int world_check_pos_ok( v2i co, int dist );
 static int cell_interactive( v2i co );
 
 void vg_update(void);
@@ -536,6 +538,12 @@ static struct cell *pcell( v2i pos )
        return &world.data[ pos[1]*world.w + pos[0] ];
 }
 
+static void lcell( int id, v2i pos )
+{
+       pos[0] = id % world.w;
+       pos[1] = (id - pos[0]) / world.w;
+}
+
 static void map_reclassify( v2i start, v2i end, int update_texbuffer )
 {
        v2i full_start = { 1,1 };
@@ -567,12 +575,12 @@ static void map_reclassify( v2i start, v2i end, int update_texbuffer )
                        u8 height = 0;
                        u8 config = 0x00;
                        
-                       if( cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT) )
+                       if( cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT|FLAG_EMITTER) )
                        {
                                for( int i = 0; i < vg_list_size( dirs ); i ++ )
                                {
                                        struct cell *neighbour = pcell((v2i){x+dirs[i][0], y+dirs[i][1]});
-                                       if( neighbour->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT) )
+                                       if( neighbour->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT|FLAG_EMITTER) )
                                                config |= 0x1 << i;
                                }
                                
@@ -597,7 +605,7 @@ static void map_reclassify( v2i start, v2i end, int update_texbuffer )
                        if( 
                                (
                                        ((cell->state & FLAG_IS_TRIGGER) && (cell->config == 0xF || cell->config == k_cell_type_split)) || 
-                                       ((cell->state & FLAG_TARGETED) && (cell->config != k_cell_type_split)) 
+                                       ((cell->state & FLAG_TARGETED) && ((cell->config != k_cell_type_split) && !(cell->state & FLAG_EMITTER))) 
                                ) && update_texbuffer
                        ){
                                cell->state &= ~(FLAG_TARGETED|FLAG_IS_TRIGGER);
@@ -882,7 +890,10 @@ static int map_load( const char *str, const char *name )
                        struct cell *cell = &row[ cx ];
                        cell->config = 0xF;
                        
-                       if( *c == '+' || *c == '-' )
+                       cell->links[0] = 0;
+                       cell->links[1] = 0;
+
+                       if( *c == '+' || *c == '-' || *c == '*' )
                        {
                                struct cell_terminal *term = arraddnptr( world.io, 1 );
                                term->pos[0] = cx;
@@ -890,8 +901,14 @@ static int map_load( const char *str, const char *name )
                                
                                term->run_count = 1;
                                term->runs[0].condition_count = 0;
+                               
+                               switch( *c )
+                               {
+                                       case '+': cell->state = FLAG_INPUT; break;
+                                       case '-': cell->state = FLAG_OUTPUT; break;
+                                       case '*': cell->state = FLAG_EMITTER; break;
+                               }
 
-                               cell->state = *c == '+'? FLAG_INPUT: FLAG_OUTPUT;
                                reg_end ++;
                        }
                        else if( *c == '#' ) cell->state = FLAG_WALL;
@@ -908,8 +925,6 @@ static int map_load( const char *str, const char *name )
                                if( cell->state & FLAG_IS_TRIGGER )
                                        arrpush( links_to_make, cx + world.h*world.w );
                                
-                               cell->links[0] = 0;
-                               cell->links[1] = 0;
                                world.score ++; 
                        }
                        else cell->state = 0x00;
@@ -919,6 +934,18 @@ static int map_load( const char *str, const char *name )
        
                c ++;
        }
+
+       // Fix emitter CC code
+       for( int i = 0; i < arrlen( world.io ); i ++ )
+       {
+               struct cell_terminal *term = &world.io[i];
+               struct cell *cell = pcell( term->pos );
+
+               if( cell->state & FLAG_EMITTER )
+               {
+                       cell->cc = term->runs[0].conditions[0];
+               }
+       }
                
        // Update data texture to fill out the background
        {
@@ -987,7 +1014,7 @@ static int map_load( const char *str, const char *name )
                        turtle[1] = 16+term->pos[1];
                        
                        turtle_dir[0] = 0;
-                       turtle_dir[1] = pcell(term->pos)->state & FLAG_INPUT? 1: -1;
+                       turtle_dir[1] = pcell(term->pos)->state & (FLAG_INPUT|FLAG_EMITTER)? 1: -1;
                        original_y = turtle_dir[1];
                        
                        info_buffer[((turtle[1]*64)+turtle[0])*4] = 0;  
@@ -1041,7 +1068,8 @@ static int map_load( const char *str, const char *name )
                        if( src->links[link_id] <= world.h*world.w )
                        {               
                                struct cell *target = &world.data[ src->links[link_id] ];
-                               if( (target->state & FLAG_CANAL) && (target->config == k_cell_type_split) )
+                               if( ((target->state & FLAG_CANAL) && (target->config == k_cell_type_split))
+                                       || (target->state & FLAG_EMITTER) )
                                {
                                        if( target->links[ link_id ] )
                                        {
@@ -1103,6 +1131,7 @@ static void map_serialize( FILE *stream )
                        if( cell->state & FLAG_WALL ) fputc( '#', stream );
                        else if( cell->state & FLAG_INPUT ) fputc( '+', stream );
                        else if( cell->state & FLAG_OUTPUT ) fputc( '-', stream );
+                       else if( cell->state & FLAG_EMITTER ) fputc( '*', stream );
                        else if( cell->state & (FLAG_CANAL|FLAG_IS_TRIGGER|FLAG_RESERVED0|FLAG_RESERVED1) ) 
                        {
                                fputc( (cell->state & (FLAG_CANAL|FLAG_IS_TRIGGER|FLAG_RESERVED0|FLAG_RESERVED1)) + (u32)'A', stream );
@@ -1394,19 +1423,28 @@ static void simulation_start(void)
        }
 }
 
-static int world_check_pos_ok( v2i co )
+static int world_check_pos_ok( v2i co, int dist )
 {
-       return (co[0] < 2 || co[0] >= world.w-2 || co[1] < 2 || co[1] >= world.h-2)? 0: 1;
+       return (co[0] < dist || co[0] >= world.w-dist || co[1] < dist || co[1] >= world.h-dist)? 0: 1;
 }
 
 static int cell_interactive( v2i co )
 {
+       struct cell *cell;
+
        // Bounds check
-       if( !world_check_pos_ok( co ) )
+       if( world_check_pos_ok( co, 1 ) )
+       {
+               cell = pcell( co );
+               if( cell->state & FLAG_EMITTER )
+                       return 1;
+       }
+
+       if( !world_check_pos_ok( co, 2 ) )
                return 0;
 
        // Flags check
-       if( world.data[ world.w*co[1] + co[0] ].state & (FLAG_WALL|FLAG_INPUT|FLAG_OUTPUT) )
+       if( cell->state & (FLAG_WALL|FLAG_INPUT|FLAG_OUTPUT) )
                return 0;
 
        // List of 3x3 configurations that we do not allow
@@ -1463,7 +1501,7 @@ static int cell_interactive( v2i co )
                {                
                        struct cell *cell = pcell((v2i){x,y});
 
-                       if( cell && (cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT)) )
+                       if( cell && (cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT|FLAG_EMITTER)) )
                                blob |= 0x1 << ((y-(co[1]-2))*5 + x-(co[0]-2));
                }
 
@@ -1607,41 +1645,43 @@ static void vg_update(void)
                        world.selected = world.tile_y * world.w + world.tile_x;
                        
                        static u32 modify_state = 0;
-                       
                        struct cell *cell_ptr = &world.data[world.selected];
-                       
-                       if( vg_get_button_down("primary") )
-                               modify_state = (cell_ptr->state & FLAG_CANAL) ^ FLAG_CANAL;
-                       
-                       if( vg_get_button("primary") && ((cell_ptr->state & FLAG_CANAL) != modify_state) )
+               
+                       if( !(cell_ptr->state & FLAG_EMITTER) )
                        {
-                               cell_ptr->state &= ~FLAG_CANAL;
-                               cell_ptr->state |= modify_state;
+                               if( vg_get_button_down("primary") )
+                                       modify_state = (cell_ptr->state & FLAG_CANAL) ^ FLAG_CANAL;
                                
-                               if( cell_ptr->state & FLAG_CANAL )
+                               if( vg_get_button("primary") && ((cell_ptr->state & FLAG_CANAL) != modify_state) )
                                {
-                                       cell_ptr->links[0] = 0;
-                                       cell_ptr->links[1] = 0;
+                                       cell_ptr->state &= ~FLAG_CANAL;
+                                       cell_ptr->state |= modify_state;
                                        
-                                       sfx_set_playrnd( &audio_tile_mod, &audio_system_sfx, 3, 6 );
-                                       world.score ++;
-                               }
-                               else
-                               {                                       
-                                       sfx_set_playrnd( &audio_tile_mod, &audio_system_sfx, 0, 3 );
-                                       world.score --;
-                               }
+                                       if( cell_ptr->state & FLAG_CANAL )
+                                       {
+                                               cell_ptr->links[0] = 0;
+                                               cell_ptr->links[1] = 0;
+                                               
+                                               sfx_set_playrnd( &audio_tile_mod, &audio_system_sfx, 3, 6 );
+                                               world.score ++;
+                                       }
+                                       else
+                                       {                                       
+                                               sfx_set_playrnd( &audio_tile_mod, &audio_system_sfx, 0, 3 );
+                                               world.score --;
+                                       }
 
-                               map_reclassify(         (v2i){ world.tile_x -2, world.tile_y -2 }, 
+                                       map_reclassify((v2i){ world.tile_x -2, world.tile_y -2 }, 
                                                                                (v2i){ world.tile_x +2, world.tile_y +2 }, 1 );
-                       }
-                       
-                       if( vg_get_button_down("secondary") && (cell_ptr->state & FLAG_CANAL) && !(cell_ptr->config == k_cell_type_split) )
-                       {
-                               world.id_drag_from = world.selected;
-                       
-                               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( vg_get_button_down("secondary") && (cell_ptr->state & FLAG_CANAL) && !(cell_ptr->config == k_cell_type_split) )
+                               {
+                                       world.id_drag_from = world.selected;
+                               
+                                       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 );
+                               }
                        }
                        
                        float local_x = vg_mouse_ws[0] - (float)world.tile_x;
@@ -1666,7 +1706,8 @@ static void vg_update(void)
                                world.id_drag_from = 0;
                        }
                        
-                       else 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|FLAG_EMITTER)) && 
+                               ((cell_ptr->config == k_cell_type_split) || (cell_ptr->state & FLAG_EMITTER)) )
                        {
                                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;
@@ -1685,17 +1726,20 @@ static void vg_update(void)
                                                current_connection->state &= ~FLAG_IS_TRIGGER;
                                                current_connection->links[ link_id ] = 0;
                                        }
-                                       
-                                       if( drag_ptr->links[ link_id ^ 0x1 ] )
+                               
+                                       for( u32 i = 0; i < 2; i ++ )
                                        {
-                                               vg_warn( "Destroying alternate link %u (%hu)\n", link_id ^ 0x1, drag_ptr->links[ link_id ^ 0x1 ] );
-                                               
-                                               struct cell *current_connection = &world.data[ drag_ptr->links[ link_id ^ 0x1 ]];
-                                               if( !current_connection->links[ link_id ] )
-                                                       current_connection->state &= ~FLAG_TARGETED;
-                                               
-                                               current_connection->links[ link_id ^ 0x1 ] = 0;
-                                               drag_ptr->links[ link_id ^ 0x1 ] = 0;
+                                               if( drag_ptr->links[ i ] )
+                                               {
+                                                       vg_warn( "Destroying link %u (%hu)\n", i, drag_ptr->links[ i ] );
+                                                       
+                                                       struct cell *current_connection = &world.data[ drag_ptr->links[ i ]];
+                                                       if( current_connection->links[ i ^ 0x1 ] == 0 )
+                                                               current_connection->state &= ~FLAG_TARGETED;
+                                                       
+                                                       current_connection->links[ i ] = 0;
+                                                       drag_ptr->links[ i ] = 0;
+                                               }
                                        }
                                        
                                        // Create the new connection
@@ -1878,7 +1922,7 @@ static void vg_update(void)
                                                }
                                                else
                                                {
-                                                       if( world_check_pos_ok( fish->pos ) )
+                                                       if( world_check_pos_ok( fish->pos, 2 ) )
                                                                fish->state = k_fish_state_bg;
                                                        else
                                                        {
@@ -1894,7 +1938,7 @@ static void vg_update(void)
                                {
                                        v2i_add( fish->pos, fish->dir, fish->pos );
                                        
-                                       if( !world_check_pos_ok( fish->pos ) )
+                                       if( !world_check_pos_ok( fish->pos, 2 ) )
                                        {
                                                fish->state = k_fish_state_dead;
                                                fish->death_time = -1000.0f;
@@ -1951,12 +1995,33 @@ static void vg_update(void)
                                                
                                                struct cell *target_peice = &world.data[ cell_current->links[trigger_id] ];
                                                
-                                               cell_current->state |= FLAG_TRIGGERED;
-                                               
-                                               if( trigger_id )
-                                                       target_peice->state |= FLAG_FLIP_FLOP;
+                                               if( target_peice->state & FLAG_EMITTER )
+                                               {
+                                                       struct fish *fish = &world.fishes[ world.num_fishes ];
+                                                       lcell( cell_current->links[trigger_id], fish->pos );
+
+                                                       fish->state = k_fish_state_soon_alive;
+                                                       fish->payload = target_peice->cc;
+                                                       
+                                                       if( target_peice->config != k_cell_type_stub )
+                                                       {
+                                                               struct cell_description *desc = &cell_descriptions[ target_peice->config ];
+                                                               v2i_copy( desc->start, fish->dir );
+                                                               fish->flow_reversed = 1;
+
+                                                               world.num_fishes ++;
+                                                               alive_count ++;
+                                                       }
+                                               }
                                                else
-                                                       target_peice->state &= ~FLAG_FLIP_FLOP;
+                                               {
+                                                       if( trigger_id )
+                                                               target_peice->state |= FLAG_FLIP_FLOP;
+                                                       else
+                                                               target_peice->state &= ~FLAG_FLIP_FLOP;
+                                               }
+
+                                               cell_current->state |= FLAG_TRIGGERED;
                                        }
                                }
                        }
@@ -2062,9 +2127,8 @@ static void vg_update(void)
                                for( int i = 0; i < arrlen( world.io ); i ++ )
                                {
                                        struct cell_terminal *term = &world.io[ i ];
-                                       int is_input = pcell(term->pos)->state & FLAG_INPUT;
                                        
-                                       if( !is_input )
+                                       if( pcell(term->pos)->state & FLAG_OUTPUT )
                                        {
                                                struct terminal_run *run = &term->runs[ world.sim_run ];
                                        
@@ -2283,7 +2347,7 @@ static void render_tiles( v2i start, v2i end, v4f const regular_colour, v4f cons
                        
                        int uv[2] = { 3, 0 };
                        
-                       if( cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT) )
+                       if( cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT|FLAG_EMITTER) )
                        {
                                uv[0] = tile_offsets[ cell->config ][0];
                                uv[1] = tile_offsets[ cell->config ][1];
@@ -2744,9 +2808,10 @@ 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;
+                                       struct cell *other_cell = &world.data[ cell->links[ trigger_id ]];
+                                       
+                                       struct cell_description *desc = &cell_descriptions[ cell->config ];
                                        
                                        int x2 = cell->links[trigger_id] % world.w;
                                        int y2 = (cell->links[trigger_id] - x2) / world.w;
@@ -2762,7 +2827,19 @@ void vg_render(void)
                                        
                                        v2_add( desc->trigger_pos, endpoint, endpoint );
                                        
-                                       glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, trigger_id? wire_right_colour: wire_left_colour );
+                                       if( other_cell->state & FLAG_EMITTER )
+                                       {
+                                               v4f wire_colour;
+                                               colour_code_v3( other_cell->cc, wire_colour );
+                                               wire_colour[3] = 1.0f;
+
+                                               glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, wire_colour );
+                                       }
+                                       else
+                                       {
+                                               glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, trigger_id? wire_right_colour: wire_left_colour );
+                                       }
+
                                        glUniform1f( SHADER_UNIFORM( shader_wire, "uCurve" ), cell->state & FLAG_TRIGGERED? rp_x2 * 0.4f: 0.4f );
                                        glUniform1f( SHADER_UNIFORM( shader_wire, "uGlow" ), cell->state & FLAG_TRIGGERED? rp_xa: 0.0f );
                                        glUniform3f( SHADER_UNIFORM( shader_wire, "uStart" ), startpoint[0], startpoint[1], 0.18f );
@@ -2790,10 +2867,11 @@ 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;
+                                       struct cell *other_cell = &world.data[ cell->links[ trigger_id ]];
                                        
+                                       struct cell_description *desc = &cell_descriptions[ cell->config ];
+                               
                                        int x2 = cell->links[trigger_id] % world.w;
                                        int y2 = (cell->links[trigger_id] - x2) / world.w;
                                        
@@ -2807,8 +2885,22 @@ void vg_render(void)
                                        
                                        v2_add( desc->trigger_pos, pts[1], pts[1] );
                                        
-                                       glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 
-                                                       1, trigger_id? wire_right_colour: wire_left_colour );
+                                       if( other_cell->state & FLAG_EMITTER )
+                                       {
+                                               v4f wire_colour;
+                                               colour_code_v3( other_cell->cc, wire_colour );
+
+                                               v3_muls( wire_colour, 0.8f, wire_colour );
+                                               wire_colour[3] = 1.0f;
+
+                                               glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, wire_colour );
+                                       }
+                                       else
+                                       {
+                                               glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, trigger_id? wire_right_colour: wire_left_colour );
+                                       }
+                                       //glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 
+                                       //              1, trigger_id? wire_right_colour: wire_left_colour );
                                        
                                        for( int i = 0; i < 2; i ++ )
                                        {
@@ -2851,6 +2943,10 @@ void vg_render(void)
        for( int i = 0; i < arrlen( world.io ); i ++ )
        {
                struct cell_terminal *term = &world.io[ i ];
+               
+               if( pcell(term->pos)->state & FLAG_EMITTER )
+                       continue;
+
                int is_input = pcell(term->pos)->state & FLAG_INPUT;
 
                v4f dot_colour = { 0.0f, 0.0f, 0.0f, 1.0f };
@@ -3043,6 +3139,7 @@ void vg_ui(void)
 #if STEAM_LEADERBOARDS
 void leaderboard_dispatch_score(void)
 {
+
        sw_upload_leaderboard_score( 
                ui_data.upload_request.level->steam_leaderboard, 
                k_ELeaderboardUploadScoreMethodKeepBest,