+
+struct cmp_level
+{
+ const char *map_name;
+ const char *title;
+ const char *description;
+ const char *achievement;
+
+ int unlocked;
+ int completed_score;
+
+ int _unlock, _linked; // When completed, unlock this level
+ struct cmp_level *unlock, *linked;
+
+ struct world_string
+ {
+ enum placement
+ {
+ k_placement_top,
+ k_placement_bottom
+ }
+ placement;
+
+ const char *str;
+ }
+ strings[2];
+
+ int serial_id;
+ int is_tutorial;
+
+ struct world_button btn;
+
+ #ifdef VG_STEAM
+ SteamLeaderboard_t steam_leaderboard;
+ #endif
+};
+
+static struct cmp_level cmp_levels_tutorials[] =
+{
+ {
+ .serial_id = 0,
+ .title = "PRINCIPLE 1",
+ .map_name = "cmp_t01",
+ .description =
+ "",
+
+ ._unlock = 1,
+ .is_tutorial = 1
+ },
+ {
+ .serial_id = 1,
+ .title = "PRINCIPLE 2",
+ .map_name = "cmp_t02",
+ .description =
+ "",
+
+ ._unlock = 2,
+ .is_tutorial = 1,
+ },
+ {
+ .serial_id = 2,
+ .title = "PRINCIPLE 3",
+ .map_name = "cmp_t03",
+ .description =
+ "",
+
+ ._unlock = 12,
+ .is_tutorial = 1
+ },
+ {
+ .serial_id = 12,
+ .title = "PRINCIPLE 4",
+ .map_name = "cmp_t04",
+ .description =
+ "",
+
+ ._unlock = 6,
+ .is_tutorial = 1,
+ .achievement = "TUTORIALS"
+ },
+ {
+ .serial_id = 15,
+ .title = "PRINCIPLE 5",
+ .map_name = "cmp_b10",
+ .description =
+ "",
+
+ ._unlock = 16,
+ .is_tutorial = 1
+ },
+ {
+ .serial_id = 17,
+ .title = "PRINCIPLE 6",
+ .map_name = "cmp_b11",
+ .description =
+ "(Right click)",
+
+ ._unlock = 18,
+ .is_tutorial = 1
+ },
+ {
+ .serial_id = 26,
+ .title = "PRINCIPLE 7",
+ .map_name = "cmp_p7",
+ .description = "Emitters",
+ ._unlock = 27,
+ .is_tutorial = 1
+ }
+};
+
+static struct cmp_level cmp_levels_basic[] =
+{
+ {
+ .serial_id = 6,
+ .title = "PATCH",
+ .map_name = "cmp_b04",
+ .description =
+ "",
+
+ ._unlock = 7,
+ ._linked = 3
+ },
+ {
+ .serial_id = 3,
+ .title = "SUBDIVISION 1",
+ .map_name = "cmp_b01",
+ .description =
+ "",
+
+ ._linked = 4,
+ ._unlock = 5
+ },
+ {
+ .serial_id = 4,
+ .title = "SUBDIVISION 2",
+ .map_name = "cmp_b02",
+ .description =
+ "",
+
+ ._unlock = 7
+ },
+ {
+ .serial_id = 5,
+ .title = "RESTRUCTURE",
+ .map_name = "cmp_b03",
+ .description =
+ "",
+
+ ._unlock = 8
+ },
+ {
+ .serial_id = 7,
+ .title = "PATTERNS 1",
+ .map_name = "cmp_b05",
+ .description =
+ "",
+
+ ._unlock = 15,
+ ._linked = 8
+ },
+ {
+ .serial_id = 8,
+ .title = "PATTERNS 2",
+ .map_name = "cmp_b06",
+ .description =
+ "",
+
+ ._unlock = 15
+ },
+ {
+ .serial_id = 16,
+ .title = "ROUTING PROBLEM",
+ .map_name = "cmp_routing",
+ .description =
+ "",
+
+ ._linked = 9
+ },
+ {
+ .serial_id = 9,
+ .title = "MIGHTY CONSUMER",
+ .map_name = "cmp_b07",
+ .description =
+ "",
+
+ ._linked = 10,
+ ._unlock = 11,
+ .achievement = "MIGHTY_CONSUMER"
+ },
+ {
+ .serial_id = 10,
+ .title = "SHIFT",
+ .map_name = "cmp_b08",
+ .description =
+ "",
+
+ ._unlock = 17
+ },
+ {
+ .serial_id = 11,
+ .title = "REVERSE",
+ .map_name = "cmp_b09",
+ .description =
+ "",
+
+ ._unlock = 17
+ },
+ {
+ .serial_id = 18,
+ .title = "NOT GATE",
+ .map_name = "cmp_not",
+ .description = "",
+
+ ._linked = 19,
+ ._unlock = 20
+ },
+ {
+ .serial_id = 19,
+ .title = "AND GATE",
+ .map_name = "cmp_and",
+ .description = "",
+
+ ._unlock = 20
+ },
+ {
+ .serial_id = 20,
+ .title = "QUALIFICATION PROJECT",
+ .map_name = "cmp_xor",
+ .description = "",
+
+ ._unlock = 25,
+ .achievement = "GRADUATE"
+ },
+ {
+ .serial_id = 27,
+ .title = "EXPAND",
+ .map_name = "cmp_expander",
+ .description = "",
+
+ ._unlock = 28
+ },
+ {
+ .serial_id = 28,
+ .title = "PATTERNS 3",
+ .map_name = "cmp_pattern3",
+ .description = "",
+ ._linked = 29
+ },
+ {
+ .serial_id = 29,
+ .title = "ROUTING PROBLEM 2",
+ .map_name = "cmp_routing2",
+ .description = "Spaghetti!",
+ ._linked = 30
+ },
+ {
+ .serial_id = 30,
+ .title = "EXACTLY 5",
+ .map_name = "cmp_exact5",
+ .description = ""
+ }
+};
+
+static struct cmp_level cmp_levels_grad[] =
+{
+ // r2
+ {
+ .serial_id = 13,
+ .title = "SORT",
+ .map_name = "cmp_i01",
+ .description = "",
+ ._linked = 14
+
+ },
+ // r2
+ {
+ .serial_id = 14,
+ .title = "THIRDS",
+ .map_name = "cmp_i02",
+ .description = "",
+ ._linked = 21
+
+ },
+ {
+ .serial_id = 21,
+ .title = "SIMPLE ADDITION",
+ .map_name = "cmp_grad",
+ .description = "",
+
+ ._linked = 22,
+ ._unlock = 23
+ },
+ {
+ .serial_id = 22,
+ .title = "SECRET CODE",
+ .map_name = "cmp_secret",
+ .description = "",
+
+ ._unlock = 23
+ }
+};
+
+static struct cmp_level cmp_levels_computer[] =
+{
+ {
+ .serial_id = 23,
+ .title = "3 BIT BINARY",
+ .map_name = "cmp_binary",
+ .description = "convert amount to binary",
+ .strings =
+ {
+ {
+ .placement = k_placement_bottom,
+ .str =
+"\t\t\t\t\t\t\t\t\t\t\x83 \x84\n"
+"\t\t\t\t\t\t\t\t\t\t\x83 \x84 Binary\n"
+"\t\t\t\t\t\t\t\t\t\t\x83 4 2 1 \x84"
+ },
+ {
+ .placement = k_placement_top,
+ .str =
+"\n"
+"\t\t\t\t\t\t\t\t\t\t\t Count"
+ }
+ },
+
+ ._unlock = 24
+ },
+ {
+ .serial_id = 24,
+ .title = "3 BIT ADDER",
+ .map_name = "cmp_add3b",
+ .description = "binary addition",
+ .strings =
+ {
+ {
+ .placement = k_placement_top,
+ //.str ="\t\t\t\t\t\t\t\t\t| NUMBER A | | NUMBER B |\n"
+ .str =""
+"\t\t\t\t\t\t\t\t\t\x8A 4 2 1 \x8B \x8A 4 2 1 \x8B\n"
+"\t\t\t\t\t\t\t\t\t\x83 \x84 add \x83 \x84\n"
+"\t\t\t\t\t\t\t\t\t\x83 \x84 \x83 \x84"
+ },
+ {
+ .placement = k_placement_bottom,
+ .str =
+"\t\t\t\x83 \x84\n"
+"\t\t\t\x83 \x84 result a+b\n"
+"\t\t\t\x83 8 4 2 1 \x84"
+ }
+ },
+
+ ._unlock = 25
+ },
+ {
+ .serial_id = 25,
+ .title = "3x3 PLOT",
+ .map_name = "cmp_plot3x3",
+ .description = "2 bit x/y",
+
+ .strings =
+ {
+ {
+ .placement = k_placement_top,
+ .str=
+"\t\t\t\t\t\t\t\t\x8A 2 1 \x8B \x8A 2 1 \x8B\n"
+"\t\t\t\t\t\t\t\t\x83 \x84 X Y \x83 \x84\n"
+"\t\t\t\t\t\t\t\t\x83 \x84 \x83 \x84"
+ }
+ }
+ }
+};
+
+#define NUM_CAMPAIGN_LEVELS (vg_list_size( cmp_levels_tutorials ) + vg_list_size( cmp_levels_basic ) + vg_list_size( cmp_levels_grad ) + vg_list_size( cmp_levels_computer ) )
+
+static struct career_level_pack
+{
+ struct cmp_level *pack;
+ int count;
+
+ v3f primary_colour;
+ v2i origin;
+ v2i dims;
+}
+career_packs[] =
+{
+ {
+ .pack = cmp_levels_tutorials,
+ .count = vg_list_size( cmp_levels_tutorials ),
+ .primary_colour = { 0.204f, 0.345f, 0.553f },
+ .origin = { -5, -2 },
+ .dims = { 1, 7 }
+ },
+ {
+ .pack = cmp_levels_basic,
+ .count = vg_list_size( cmp_levels_basic ),
+ .primary_colour = { 0.304f, 0.245f, 0.553f },
+ .origin = { -3, -2 },
+ .dims = { 3, 7 }
+ },
+ {
+ .pack = cmp_levels_grad,
+ .count = vg_list_size( cmp_levels_grad ),
+ .primary_colour = { 0.553f, 0.345f, 0.204f },
+ .origin = { -5, 6 },
+ .dims = { 5, 1 }
+ },
+ {
+ .pack = cmp_levels_computer,
+ .count = vg_list_size( cmp_levels_computer ),
+ .primary_colour = { 0.75f, 0.23f, 0.39f },
+ .origin = { -5, 8 },
+ .dims = { 5, 2 }
+ }
+};
+
+// Setup pointers and that
+static void career_local_data_init(void)
+{
+ struct cmp_level *level_ptrs[ NUM_CAMPAIGN_LEVELS ];
+ for( int i = 0; i < NUM_CAMPAIGN_LEVELS; i ++ )
+ level_ptrs[i] = NULL;
+
+ // COllect pointers
+ for( int i = 0; i < vg_list_size( career_packs ); i ++ )
+ {
+ struct career_level_pack *set = &career_packs[i];
+
+ for( int j = 0; j < set->count; j ++ )
+ {
+ int id = set->pack[j].serial_id;
+
+ if( level_ptrs[ id ] )
+ vg_error( "Serial id %u already used!\n", id );
+ else
+ level_ptrs[ set->pack[j].serial_id ] = &set->pack[j];
+ }
+ }
+
+ // Apply
+ for( int i = 0; i < vg_list_size( career_packs ); i ++ )
+ {
+ struct career_level_pack *set = &career_packs[i];
+
+ for( int j = 0; j < set->count; j ++ )
+ {
+ struct cmp_level *lvl = &set->pack[j];
+
+ if( lvl->_unlock >= NUM_CAMPAIGN_LEVELS ||
+ lvl->_linked >= NUM_CAMPAIGN_LEVELS )
+ {
+ vg_error( "_unlock / _linked out of range (%d, %d)\n",
+ lvl->_unlock, lvl->_linked );
+ }
+ else
+ {
+ lvl->unlock = lvl->_unlock? level_ptrs[ lvl->_unlock ]: NULL;
+ lvl->linked = lvl->_linked? level_ptrs[ lvl->_linked ]: NULL;
+ }
+ }
+ }
+}