"thirds"
};
-#pragma pack(push,1)
-struct dcareer_state
-{
- u32 version;
- i32 total_unlocked;
-
- u32 reserved[14];
-
- struct dlevel_state
- {
- i32 score;
- i32 reserved[3];
- }
- levels[ NUM_CAMPAIGN_LEVELS ];
-};
-#pragma pack(pop)
-
-static void career_serialize(void)
-{
- struct dcareer_state encoded;
- encoded.version = 2;
- encoded.total_unlocked = career_local.total_unlocked;
-
- for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
- {
- struct serializable_set *set = &career_serializable[i];
-
- for( int j = 0; j < set->count; j ++ )
- {
- struct cmp_level *lvl = &set->pack[j];
- struct dlevel_state *dest = &encoded.levels[lvl->serial_id];
-
- dest->score = lvl->completed_score;
- dest->reserved[0] = 0;
- dest->reserved[1] = 0;
- dest->reserved[2] = 0;
- }
- }
-
- vg_asset_write( "sav/game.sv2", &encoded, sizeof( struct dcareer_state ) );
-}
-
-static void career_load(void)
-{
- i64 sz;
- struct dcareer_state encoded;
- memset( (void*)&encoded, 0, sizeof( struct dcareer_state ) );
-
- // Load and copy data into encoded
- void *cr = vg_asset_read_s( "sav/game.sv2", &sz );
-
- if( cr )
- {
- if( sz > sizeof( struct dcareer_state ) )
- vg_warn( "This save file is too big! Some levels will be lost\n" );
-
- if( sz <= offsetof( struct dcareer_state, levels ) )
- {
- vg_warn( "This save file is too small to have a header. Creating a blank one\n" );
- free( cr );
- return;
- }
-
- memcpy( (void*)&encoded, cr, VG_MIN( sizeof( struct dcareer_state ), sz ) );
- free( cr );
- }
- else
- vg_info( "No save file... Using blank one\n" );
-
- // Decode everything from dstate
- for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
- {
- struct serializable_set *set = &career_serializable[i];
-
- for( int j = 0; j < set->count; j ++ )
- {
- struct cmp_level *lvl = &set->pack[j];
- struct dlevel_state *src = &encoded.levels[lvl->serial_id];
-
- lvl->completed_score = src->score;
- // ...
- }
- }
-}
-
m3x3f m_projection;
m3x3f m_view;
m3x3f m_mdl;
u32 score;
u32 completed;
u32 time;
-} world = {};
+} world;
void leaderboard_set_score( struct cmp_level *cmp_level, u32 score );
return 0;
}
+#pragma pack(push,1)
+struct dcareer_state
+{
+ u32 version;
+ i32 in_map;
+
+ u32 reserved[14];
+
+ struct dlevel_state
+ {
+ i32 score;
+ i32 unlocked;
+ i32 reserved[2];
+ }
+ levels[ NUM_CAMPAIGN_LEVELS ];
+};
+#pragma pack(pop)
+
+static void career_serialize(void)
+{
+ struct dcareer_state encoded;
+ encoded.version = 2;
+ encoded.in_map = world.pCmpLevel? world.pCmpLevel->serial_id: -1;
+
+ memset( encoded.reserved, 0, sizeof( encoded.reserved ) );
+
+ for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
+ {
+ struct serializable_set *set = &career_serializable[i];
+
+ for( int j = 0; j < set->count; j ++ )
+ {
+ struct cmp_level *lvl = &set->pack[j];
+ struct dlevel_state *dest = &encoded.levels[lvl->serial_id];
+
+ dest->score = lvl->completed_score;
+ dest->unlocked = lvl->unlocked;
+ dest->reserved[0] = 0;
+ dest->reserved[1] = 0;
+ }
+ }
+
+ vg_asset_write( "sav/game.sv2", &encoded, sizeof( struct dcareer_state ) );
+}
+
+static void career_unlock_level( struct cmp_level *lvl );
+static void career_unlock_level( struct cmp_level *lvl )
+{
+ lvl->unlocked = 1;
+
+ if( lvl->linked )
+ career_unlock_level( lvl->linked );
+}
+
+static void career_pass_level( struct cmp_level *lvl, int score, int upload )
+{
+ if( score > 0 )
+ {
+ if( score < lvl->completed_score || lvl->completed_score == 0 )
+ {
+ if( !lvl->is_tutorial && upload )
+ leaderboard_set_score( lvl, score );
+
+ lvl->completed_score = score;
+ }
+
+ if( lvl->unlock ) career_unlock_level( lvl->unlock );
+ }
+}
+
+static void career_reset_level( struct cmp_level *lvl )
+{
+ lvl->unlocked = 0;
+ lvl->completed_score = 0;
+}
+
+static void career_load(void)
+{
+ i64 sz;
+ struct dcareer_state encoded;
+
+ // Blank save state
+ memset( (void*)&encoded, 0, sizeof( struct dcareer_state ) );
+ encoded.in_map = -1;
+ encoded.levels[0].unlocked = 1;
+
+ // Load and copy data into encoded
+ void *cr = vg_asset_read_s( "sav/game.sv2", &sz );
+
+ if( cr )
+ {
+ if( sz > sizeof( struct dcareer_state ) )
+ vg_warn( "This save file is too big! Some levels will be lost\n" );
+
+ if( sz <= offsetof( struct dcareer_state, levels ) )
+ {
+ vg_warn( "This save file is too small to have a header. Creating a blank one\n" );
+ free( cr );
+ return;
+ }
+
+ memcpy( (void*)&encoded, cr, VG_MIN( sizeof( struct dcareer_state ), sz ) );
+ free( cr );
+ }
+ else
+ vg_info( "No save file... Using blank one\n" );
+
+ // Reset memory
+ for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
+ {
+ struct serializable_set *set = &career_serializable[i];
+
+ for( int j = 0; j < set->count; j ++ )
+ career_reset_level( &set->pack[j] );
+ }
+
+ // Header information
+ // =================================
+
+ // Decode everything from dstate
+ for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
+ {
+ struct serializable_set *set = &career_serializable[i];
+
+ for( int j = 0; j < set->count; j ++ )
+ {
+ struct cmp_level *lvl = &set->pack[j];
+ struct dlevel_state *src = &encoded.levels[lvl->serial_id];
+
+ if( src->unlocked ) career_unlock_level( lvl );
+ if( src->score ) lvl->completed_score = src->score;
+
+ // ...
+ if( lvl->serial_id == encoded.in_map )
+ {
+ if( console_changelevel( 1, &lvl->map_name ) )
+ world.pCmpLevel = lvl;
+ }
+ }
+ }
+}
+
void leaderboard_found( LeaderboardFindResult_t *pCallback );
void leaderboard_downloaded( LeaderboardScoresDownloaded_t *pCallback );
resource_load_main();
// Restore gamestate
+ career_local_data_init();
career_load();
- console_load_map( 1, level_pack_1 );
}
void vg_free(void)
world.score = score;
world.time = world.sim_frame;
+
+ // Copy into career data
+ if( world.pCmpLevel )
+ {
+ career_pass_level( world.pCmpLevel, world.score, 1 );
+ }
}
}
else
vg_error( "Level failed :(\n" );
}
- // Copy into career data
- if( world.pCmpLevel )
- {
- if( world.score < world.pCmpLevel->completed_score || world.pCmpLevel->completed_score == 0 )
- leaderboard_set_score( world.pCmpLevel, world.score );
-
- world.pCmpLevel->completed_score = world.score;
- }
simulation_stop(); // TODO: Async?
break;
// Level title
+ // TODO: Fix this?
+ /*
ui_begin( &ui_global_ctx, 512, 256 );
ui_global_ctx.override_colour = 0xff9a8a89;
m3x3_scale( world_text, (v3f){0.01f,-0.01f,0.01f} );
ui_draw( &ui_global_ctx, world_text );
+ */
// Main
// =========================================================================================
for( int j = 0; j < term->runs[k].condition_count; j ++ )
{
float y_offset = is_input? 1.2f: -0.2f;
- y_offset += (is_input? 0.2f: -0.2f) * (float)k;
-
- glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, (float)posy + y_offset, 0.1f );
+ float y_h = (is_input? 0.2f: -0.2f) * (float)k;
if( is_input )
{
+ glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j,
+ (y_offset + (float)posy + (float)(term->run_count-1)*0.2f) - y_h, 0.1f );
+
colour_code_v3( term->runs[k].conditions[j], dot_colour );
glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour );
}
else
{
+ glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, (float)posy + y_offset + y_h, 0.1f );
+
if( term->runs[k].recv_count > j )
{
colour_code_v3( term->runs[k].recieved[j], dot_colour );
{
struct cmp_level *levels = pack_infos[ pack_selection ].levels;
int count = pack_infos[ pack_selection ].level_count;
- int unlocked = 3000;
-
+
static struct ui_scrollbar sb = {
.bar_height = 400
};
{
struct cmp_level *lvl_info = &levels[i];
- if( i < unlocked )
+ if( lvl_info->unlocked )
{
if( lvl_info->completed_score != 0 )
gui_override_colours( i&0x1? &flcol_list_complete_a: &flcol_list_complete_b );
else
gui_override_colours( &flcol_list_locked );
- if( i < unlocked )
+ if( lvl_info->unlocked )
{
if( gui_button( 2 + i ) == k_button_click )
{
gui_override_colours( &flcol_list_complete_a );
if( gui_button( 3002 ) == k_button_click )
{
- console_changelevel( 1, &ui_data.level_selected->map_name );
- world.pCmpLevel = ui_data.level_selected;
+ if( console_changelevel( 1, &ui_data.level_selected->map_name ) )
+ {
+ world.pCmpLevel = ui_data.level_selected;
- ui_data.level_selected = NULL;
- ui_data.leaderboard_show = 0;
+ ui_data.level_selected = NULL;
+ ui_data.leaderboard_show = 0;
+ }
}
gui_text( "PLAY", 6, k_text_alignment_center );
gui_end();
const char *title;
const char *description;
+ int unlocked;
int completed_score;
- int unlocks; // When completed, unlock this many levels
- int linked_unlocks; // When unlocked, unlock this many levels additionally
+ int _unlock, _linked; // When completed, unlock this level
+ struct cmp_level *unlock, *linked;
int serial_id;
+ int is_tutorial;
SteamLeaderboard_t steam_leaderboard;
};
-struct cmp_level cmp_levels_tutorials[] =
+static struct cmp_level cmp_levels_tutorials[] =
{
{
+ .serial_id = 0,
.title = "PRINCIPLE 1",
.map_name = "cmp_t01",
.description = "Utilize basic transport methods",
- .serial_id = 0,
- .unlocks = 1
+ ._unlock = 1,
+ .is_tutorial = 1
},
{
+ .serial_id = 1,
.title = "PRINCIPLE 2",
.map_name = "cmp_t02",
.description = "Utilize the twisty turny(TM) piece to split\n"
"the marble stream into two",
- .serial_id = 1,
- .unlocks = 1
+ ._unlock = 2,
+ .is_tutorial = 1,
},
{
+ .serial_id = 2,
.title = "PRINCIPLE 3",
.map_name = "cmp_t03",
.description = "Merge transport into one",
- .serial_id = 2,
- .unlocks = 1,
+ ._unlock = 12,
+ .is_tutorial = 1
},
{
+ .serial_id = 12,
.title = "PRINCIPLE 4",
.map_name = "cmp_t04",
.description = "Some stages require multiple runs to succeed\n"
"in order to pass",
- .serial_id = 12,
- .unlocks = 3
+ ._unlock = 3,
+ .is_tutorial = 1
}
};
-struct cmp_level cmp_levels_basic[] =
+static struct cmp_level cmp_levels_basic[] =
{
{
+ .serial_id = 3,
.title = "SUBDIVISION 1",
.map_name = "cmp_b01",
.description = "Simple maths, branching required.",
- .serial_id = 3,
- .unlocks = 1
+ ._linked = 4,
+ ._unlock = 6
},
{
+ .serial_id = 4,
.title = "SUBDIVISION 2",
.map_name = "cmp_b02",
.description = "Simple maths, except more.",
-
- .serial_id = 4,
- .unlocks = 1
+
+ ._linked = 5,
+ ._unlock = 7
},
{
+ .serial_id = 5,
.title = "RESTRUCTURE",
.map_name = "cmp_b03",
.description = "Not so simple swap",
- .serial_id = 5,
- .unlocks = 1
+ ._unlock = 8
},
{
+ .serial_id = 6,
.title = "SERIALIZE",
.map_name = "cmp_b04",
.description = "Merge and sort",
- .serial_id = 6,
- .unlocks = 1
+ ._unlock = 7
},
{
+ .serial_id = 7,
.title = "PATTERNS 1",
.map_name = "cmp_b05",
.description = "Replicate",
- .serial_id = 7,
- .unlocks = 1
+ ._linked = 8
},
{
+ .serial_id = 8,
.title = "PATTERNS 2",
.map_name = "cmp_b06",
.description = "Replicate MORE",
- .serial_id = 8,
- .unlocks = 1
+ ._unlock = 9
},
{
+ .serial_id = 9,
.title = "MIGHTY CONSUMER",
.map_name = "cmp_b07",
.description = "Build a greedy system",
- .serial_id = 9,
- .unlocks = 1
+ ._linked = 10,
+ ._unlock = 11
},
{
+ .serial_id = 10,
.title = "ENCRYPTED 1",
.map_name = "cmp_b08",
.description = "Some configurations may not be valid",
- .serial_id = 10,
- .unlocks = 1
+ ._unlock = 15
},
{
+ .serial_id = 11,
.title = "REVERSE",
.map_name = "cmp_b09",
.description = "Reverse the incoming order. Always length 4",
- .serial_id = 11,
- .unlocks = 1
+ ._unlock = 15
},
{
+ .serial_id = 15,
.title = "PRINCIPLE 5",
.map_name = "cmp_b10",
.description =
"of your training package, you will now be tasked to\n"
"complete them",
- .serial_id = 15,
- .linked_unlocks = 1
+ ._unlock = 16
},
{
+ .serial_id = 16,
.title = "ROUTING PROBLEM",
.map_name = "cmp_routing",
.description =
"Things can get a little chaotic on tight boards, do your\n"
"best to utilize principle 5 to get the job done\n",
- .serial_id = 16,
- .unlocks = 1
+ ._unlock = 17
},
{
+ .serial_id = 17,
.title = "PRINCIPLE 6",
.map_name = "cmp_b11",
.description =
"this results in no operation being performed, and no\n"
"state changes take place in the Twisty Turny(TM)\n",
- .serial_id = 17,
- .linked_unlocks = 1
+ ._unlock = 18
},
{
+ .serial_id = 18,
.title = "NOT GATE",
.map_name = "cmp_not",
.description =
"Test your knowledge of triggers, build an 'NOT GATE'\n"
"emulated by marble logic.",
- .serial_id = 18,
- .unlocks = 1
+ ._linked = 19,
+ ._unlock = 20
},
{
+ .serial_id = 19,
.title = "AND GATE",
.map_name = "cmp_and",
.description =
"A slightly more complicated gate, but shouldn't be\n"
"too difficult for your skillset.",
- .serial_id = 19,
- .unlocks = 1
+ ._unlock = 20
},
{
+ .serial_id = 20,
.title = "QUALIFICATION PROJECT",
.map_name = "cmp_grad",
.description =
"There's no instructions here, resolve and complete this\n"
"task to qualify yourself as an official marble engineer",
- .serial_id = 20,
- .unlocks = 3
+ ._unlock = 13
}
};
-struct cmp_level cmp_levels_grad[] =
+static struct cmp_level cmp_levels_grad[] =
{
{
+ .serial_id = 13,
.title = "SORT",
.map_name = "cmp_i01",
.description =
"Device a scheme to filter and sort the inputs. If you\n"
"believe you lack the tools required to solve this one,\n"
"take a harder look at the inputs.",
+ ._linked = 14
- .serial_id = 13
},
{
+ .serial_id = 14,
.title = "THIRDS",
.map_name = "cmp_i02",
.description =
"Split the inputs up into a third of their values\n"
"\n"
"Is this possible? -HG",
+ ._linked = 21
- .serial_id = 14
},
{
+ .serial_id = 21,
.title = "XOR CHIP",
.map_name = "cmp_xor",
.description =
"Significantly more complicated than an AND or NOT gate,\n"
"but possible.",
- .serial_id = 21
+ ._linked = 22
},
{
+ .serial_id = 22,
.title = "SECRET CODE",
.map_name = "cmp_secret",
.description =
"Only one input should send an unlock signal marble to\n"
"the output.\n"
- "The code: 100110",
- .serial_id = 22
+ "The code: 100110"
}
};
#define NUM_CAMPAIGN_LEVELS (vg_list_size( cmp_levels_tutorials ) + vg_list_size( cmp_levels_basic ) + vg_list_size( cmp_levels_grad ))
-struct
+/*
+static struct
{
- int total_unlocked;
}
career_local =
{
- .total_unlocked = 1
-};
+};*/
-struct serializable_set
+static struct serializable_set
{
struct cmp_level *pack;
int count;
.count = vg_list_size( cmp_levels_grad )
}
};
+
+// Setup pointers and that
+static void career_local_data_init(void)
+{
+ struct cmp_level *level_ptrs[ NUM_CAMPAIGN_LEVELS ];
+
+ // COllect pointers
+ for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
+ {
+ struct serializable_set *set = &career_serializable[i];
+
+ for( int j = 0; j < set->count; j ++ )
+ level_ptrs[ set->pack[j].serial_id ] = &set->pack[j];
+ }
+
+ // Apply
+ for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
+ {
+ struct serializable_set *set = &career_serializable[i];
+
+ for( int j = 0; j < set->count; j ++ )
+ {
+ struct cmp_level *lvl = &set->pack[j];
+ lvl->unlock = lvl->_unlock? level_ptrs[ lvl->_unlock ]: NULL;
+ lvl->linked = lvl->_linked? level_ptrs[ lvl->_linked ]: NULL;
+ }
+ }
+}