#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
u16 state;
u16 links[2];
u8 config;
- u8 pad0;
+ char cc;
}
*data;
#pragma pack(pop)
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 );
// -------------
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);
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 };
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;
}
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);
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;
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;
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;
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
{
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;
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 ] )
{
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 );
}
}
-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
{
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));
}
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;
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;
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
}
else
{
- if( world_check_pos_ok( fish->pos ) )
+ if( world_check_pos_ok( fish->pos, 2 ) )
fish->state = k_fish_state_bg;
else
{
{
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;
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;
}
}
}
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 ];
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];
{
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;
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 );
{
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;
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 ++ )
{
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 };
#if STEAM_LEADERBOARDS
void leaderboard_dispatch_score(void)
{
+
sw_upload_leaderboard_score(
ui_data.upload_request.level->steam_leaderboard,
k_ELeaderboardUploadScoreMethodKeepBest,