2 // ===========================================================================================================
4 vg_tex2d tex_tile_data
= { .path
= "textures/tileset.qoi" };
5 vg_tex2d tex_tile_detail
= { .path
= "textures/tile_overlays.qoi" };
6 vg_tex2d tex_wood
= { .path
= "textures/wood.qoi" };
7 vg_tex2d tex_background
= { .path
= "textures/background.qoi" };
8 vg_tex2d tex_ball_noise
= { .path
= "textures/bnoise.qoi" };
9 vg_tex2d tex_monofur
= { .path
= "textures/ascii.qoi", .flags
= VG_TEXTURE_NO_MIP
};
10 vg_tex2d tex_unkown
= { .path
= "textures/unkown.qoi" };
11 vg_tex2d tex_buttons
= { .path
= "textures/buttons.qoi" };
13 vg_tex2d
*texture_list
[] = { &tex_tile_detail
, &tex_tile_data
, &tex_wood
, &tex_background
, &tex_ball_noise
, &tex_monofur
, &tex_unkown
, &tex_buttons
};
16 // ===========================================================================================================
18 sfx_vol_control audio_volume_sfx
= { .val
= 1.0f
, .name
= "Sound effects" };
19 sfx_vol_control audio_volume_music
= { .val
= 1.0f
, .name
= "Music" };
21 sfx_system audio_system_sfx
=
25 .vol_src
= &audio_volume_sfx
,
29 sfx_set audio_tile_mod
=
41 sfx_set audio_splitter
=
44 sound/splitter_01.ogg\0"
50 sound/rolling_01.ogg\0\
51 sound/rolling_02.ogg\0"
54 sfx_set audio_random
=
57 sound/random_01.ogg\0\
58 sound/random_02.ogg\0\
59 sound/random_03.ogg\0\
60 sound/random_04.ogg\0\
61 sound/random_05.ogg\0\
62 sound/random_06.ogg\0\
63 sound/random_07.ogg\0\
64 sound/random_08.ogg\0"
67 sfx_set audio_clicks
=
75 // One two or three layers of rolling noise
76 sfx_system audio_system_balls_rolling
=
78 .vol
= 1.f
, .ch
= 1, .vol_src
= &audio_volume_sfx
,
79 .name
= "Balls Rolling", .flags
= SFX_FLAG_REPEAT
83 sfx_system audio_system_balls_switching
=
85 .vol
= 1.f
, .ch
= 1, .vol_src
= &audio_volume_sfx
,
86 .name
= "Balls Switching"
89 // Gameplay critical sounds eg. splitter sound rocking
90 sfx_system audio_system_balls_important
=
92 .vol
= 1.f
, .ch
= 1, .vol_src
= &audio_volume_sfx
,
93 .name
= "Balls Gameplay"
97 sfx_system audio_system_balls_extra
=
99 .vol
= 1.f
, .ch
= 1, .vol_src
= &audio_volume_sfx
,
100 .name
= "Balls Extra"
103 sfx_system audio_system_ui
=
105 .vol
= 1.f
, .ch
= 1, .vol_src
= &audio_volume_sfx
,
109 ui_colourset ui_fl_colours
= {
115 ui_colourset ui_fl_colours_inactive
= {
121 static void resource_load_main(void)
124 vg_tex2d_init( texture_list
, vg_list_size( texture_list
) );
126 ui_override_font( tex_monofur
.name
, 7 );
128 ui_global_ctx
.colours_main
= &ui_fl_colours
;
132 sfx_set_init( &audio_tile_mod
, NULL
);
133 sfx_set_init( &audio_splitter
, NULL
);
134 sfx_set_init( &audio_rolls
, NULL
);
135 sfx_set_init( &audio_random
, NULL
);
136 sfx_set_init( &audio_clicks
, NULL
);
139 static void resource_free_main(void)
141 vg_tex2d_free( texture_list
, vg_list_size( texture_list
) );
143 sfx_set_free( &audio_tile_mod
);
144 sfx_set_free( &audio_splitter
);
145 sfx_set_free( &audio_rolls
);
146 sfx_set_free( &audio_random
);
147 sfx_set_free( &audio_clicks
);
151 // ===========================================================================================================
153 SHADER_DEFINE( shader_tile_colour
,
156 "layout (location=0) in vec2 a_co;"
158 "uniform vec3 uOffset;"
162 "gl_Position = vec4( uPv * vec3( a_co * uOffset.z + uOffset.xy, 1.0 ), 1.0 );"
166 "out vec4 FragColor;"
167 "uniform vec4 uColour;"
171 "FragColor = uColour;"
174 UNIFORMS({ "uPv", "uOffset", "uColour" })
177 SHADER_DEFINE( shader_ball
,
179 "layout (location=0) in vec2 a_co;"
180 "uniform vec3 uOffset;"
183 "out vec4 aTexCoords;"
188 "vec3 worldpos = vec3( (a_co * 0.5 - 0.25) * uOffset.z + uOffset.xy, 1.0 );"
189 "gl_Position = vec4( uPv * worldpos, 1.0 );"
191 // Create texture coords
192 "aTexCoords = vec4( a_co, worldpos.xy );"
196 "out vec4 FragColor;"
198 "uniform sampler2D uTexMain;"
199 "uniform vec3 uColour;"
200 "uniform vec2 uTexOffset;"
202 "in vec4 aTexCoords;"
206 "vec2 center_coords = aTexCoords.xy - 0.5;"
207 "vec2 center_coords_sqr = center_coords*center_coords;"
208 "float circle_factor = smoothstep( 0.07, 0.0625, center_coords_sqr.x+center_coords_sqr.y );"
210 "float bulge_amt = center_coords_sqr.x+center_coords_sqr.y;"
211 "vec2 warped_coords = aTexCoords.zw+uTexOffset - center_coords;"
212 "vec4 noise_sample = texture( uTexMain, warped_coords );"
214 "float rim_light = (center_coords_sqr.x+center_coords_sqr.y)*15.0;"
216 "vec2 shadow_coords = center_coords + vec2(0.02,0.07);"
217 "vec2 shadow_coords_sqr = shadow_coords*shadow_coords;"
218 "float shadow = exp(-((shadow_coords_sqr.x+shadow_coords_sqr.y)-0.0125)*15.0);"
220 "vec3 marble_comp = uColour*0.9 + (noise_sample.x*0.7+pow(rim_light,3.0)*2.0) * 0.1;"
221 "vec4 colour_comp = mix( vec4(0.74,0.53,0.34,shadow), vec4(marble_comp,1.0), circle_factor );"
223 "FragColor = colour_comp;"
226 UNIFORMS({ "uTexMain", "uColour", "uOffset", "uPv", "uTexOffset" })
229 SHADER_DEFINE( shader_tile_main
,
231 "layout (location=0) in vec2 a_co;"
232 "uniform vec4 uOffset;" // Tile x/y, uv x/y
234 "uniform mat2 uSubTransform;"
236 "out vec4 aTexCoords;"
237 "out vec2 aWorldCoords;"
239 "vec2 hash22(vec2 p)"
241 "vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));"
242 "p3 += dot(p3, p3.yzx+33.33);"
243 "return fract((p3.xx+p3.yz)*p3.zy);"
249 "vec2 subtransform = uSubTransform * (a_co-0.5) + 0.5;"
250 "vec3 worldpos = vec3( subtransform + uOffset.xy, 1.0 );"
251 "gl_Position = vec4( uPv * worldpos, 1.0 );"
253 // Create texture coords
254 "vec2 random_offset = floor(hash22(uOffset.xy) * 4.0) * 0.25;"
255 "vec2 edge_safe_coords = a_co * 0.98 + 0.01;"
256 "aTexCoords = vec4((edge_safe_coords + uOffset.zw) * 0.25, edge_safe_coords * 0.25 + random_offset );"
257 "aWorldCoords = worldpos.xy;"
261 "out vec4 FragColor;"
263 "uniform sampler2D uTexGlyphs;"
264 "uniform sampler2D uTexWood;"
265 "uniform float uGhost;"
266 "uniform float uForeground;"
267 "uniform vec2 uMousePos;"
268 "uniform vec4 uColour;"
270 "in vec4 aTexCoords;"
271 "in vec2 aWorldCoords;"
275 "vec3 shadowing_colour = vec3( 0.93, 0.88536, 0.8184 ) * 0.97;"
276 "vec4 glyph = texture( uTexGlyphs, aTexCoords.xy );"
277 "vec4 wood = texture( uTexWood, aTexCoords.zw );"
278 "vec4 wood_secondary = texture( uTexWood, aTexCoords.zw + 0.25 );"
279 "vec3 wood_comp = mix( wood_secondary.rgb * shadowing_colour, wood.rgb, clamp( glyph.b * 2.0 - 1.0, 0.0, 1.0 ) );"
281 "vec3 shadows = mix( vec3( 0.85, 0.7344, 0.561 ), vec3(1.0,1.0,1.0), glyph.r );"
283 "vec4 output_regular = vec4( wood_comp * shadows, mix( glyph.a, glyph.b, uForeground ) );"
285 "float ghost_dist = clamp( 1.5 - distance(uMousePos, aWorldCoords), 0.0, 1.0 );"
286 "vec4 output_ghost = vec4( 1.0, 1.0, 1.0, glyph.g * ghost_dist );"
288 "FragColor = mix( output_regular, output_ghost, uGhost ) * uColour;"
291 UNIFORMS({ "uPv", "uOffset", "uTexGlyphs", "uTexWood", "uSubTransform", "uGhost", "uMousePos", "uColour", "uForeground" })
294 SHADER_DEFINE( shader_background
,
296 "layout (location=0) in vec2 a_co;"
298 "uniform vec3 uOffset;"
300 "out vec2 aTexCoords;"
304 "vec2 world_pos = a_co * uOffset.z + uOffset.xy;"
305 "gl_Position = vec4( uPv * vec3( world_pos, 1.0 ), 1.0 );"
310 "out vec4 FragColor;"
312 "uniform sampler2D uTexMain;"
313 "uniform sampler2D uSamplerNoise;"
314 "uniform float uVariance;"
316 "in vec2 aTexCoords;"
320 "float ao_accum = 0.0;"
321 "for( int i=0; i<10; ++i )"
323 "vec2 random_noise = (texture( uSamplerNoise, aTexCoords * 20.0 + float(i) * 0.2 ).xy - vec2( 0.5, 0.5 )) * uVariance;"
324 "vec4 background = texture( uTexMain, aTexCoords + random_noise );"
325 "ao_accum += background.r * clamp((1.0 - length( random_noise )), 0.0, 1.0);"
329 "vec4 data_this_tile = texture( uTexMain, aTexCoords );"
331 "ao_accum -= data_this_tile.r;"
333 "vec3 colour_main = mix( vec3( 0.369768, 0.3654, 0.42 ),vec3( 0.275, 0.388, 0.553 ), data_this_tile.g );"
335 "vec2 square_coords = fract( aTexCoords * 64.0 );"
336 "vec2 grid_coords = abs( square_coords - 0.5 );"
337 "float edge_contrast = (1.0-ao_accum*0.2);"
339 "float gridline = step( 0.49, max(grid_coords.x,grid_coords.y) );"
340 "float gridline_fadeout = min(max(edge_contrast-1.0, 0.0)*40.0 + data_this_tile.g,10.0);"
342 "FragColor = vec4( colour_main * edge_contrast + gridline * 0.02 * gridline_fadeout, 1.0 );"
345 UNIFORMS({ "uPv", "uOffset", "uTexMain", "uVariance", "uSamplerNoise" })
348 SHADER_DEFINE( shader_wire
,
350 "layout (location=0) in vec2 a_co;"
351 "uniform vec3 uStart;"
354 "uniform float uCurve;"
356 "out vec2 aTexCoords;"
358 "vec3 sample_curve_time( float t )"
360 "vec3 line_coord = mix( uStart, uEnd, t );"
362 "float curve_amt = 1.0-(pow((t*2.0-1.0),2.0));"
363 "return vec3( line_coord.x, line_coord.y - curve_amt*uCurve, line_coord.z );"
369 "vec3 p0 = sample_curve_time( a_co.x );"
370 "vec3 p1 = sample_curve_time( a_co.x + 0.025 );"
372 "vec2 line_tangent = normalize(p1.xy-p0.xy);"
373 "vec2 line_normal = vec2( -line_tangent.y, line_tangent.x );"
375 "vec2 worldfinal = p0.xy + line_normal*a_co.y*p0.z;"
377 "gl_Position = vec4( uPv * vec3(worldfinal, 1.0), 1.0 );"
379 // Create texture coords (todo: include stretch adjusted coords?)
380 "aTexCoords = vec2( a_co.x, a_co.y + 0.5 );"
384 "out vec4 FragColor;"
386 "uniform sampler2D uTexMain;"
387 "uniform vec4 uColour;"
389 "in vec2 aTexCoords;"
393 "FragColor = uColour;"
396 UNIFORMS({ "uPv", "uColour", "uTexMain", "uStart", "uEnd", "uCurve" })
399 SHADER_DEFINE( shader_buttons
,
401 "layout (location=0) in vec2 a_co;"
402 "uniform vec4 uOffset;" // Tile x/y, uv x/y
405 "out vec2 aTexCoords;"
410 "vec3 worldpos = vec3( a_co + uOffset.xy, 1.0 );"
411 "gl_Position = vec4( uPv * worldpos, 1.0 );"
413 // Create texture coords
414 "vec2 edge_safe_coords = a_co * 0.98 + 0.01;"
415 "aTexCoords = (edge_safe_coords + uOffset.zw) * 0.25;"
419 "out vec4 FragColor;"
421 "uniform sampler2D uTexMain;"
422 "uniform vec4 uColour;" // rgb, light amount
424 "in vec2 aTexCoords;"
428 "vec4 glyph = texture( uTexMain, aTexCoords.xy );"
430 "FragColor = vec4( uColour.rgb * (mix(glyph.r, glyph.g, uColour.a)+0.02)*2.6 + glyph.b * 0.4, glyph.a );"
433 UNIFORMS({ "uPv", "uOffset", "uTexMain", "uColour" })
437 void vg_register(void)
439 SHADER_INIT( shader_tile_colour
);
440 SHADER_INIT( shader_tile_main
);
441 SHADER_INIT( shader_ball
);
442 SHADER_INIT( shader_background
);
443 SHADER_INIT( shader_wire
);
444 SHADER_INIT( shader_buttons
);
448 0000 0 | 0001 1 | 0010 2 | 0011 3
452 0100 4 | 0101 5 | 0110 6 | 0111 7
456 1000 8 | 1001 9 | 1010 10 | 1011 11
460 1100 12 | 1101 13 | 1110 14 | 1111 15
466 float const MESH_NUMBER_0
[] = {
467 #include "fonts/numbers/n0.h"
470 float const MESH_NUMBER_1
[] = {
471 #include "fonts/numbers/n1.h"
474 float const MESH_NUMBER_2
[] = {
475 #include "fonts/numbers/n2.h"
478 float const MESH_NUMBER_3
[] = {
479 #include "fonts/numbers/n3.h"
482 float const MESH_NUMBER_4
[] = {
483 #include "fonts/numbers/n4.h"
486 float const MESH_NUMBER_5
[] = {
487 #include "fonts/numbers/n5.h"
490 float const MESH_NUMBER_6
[] = {
491 #include "fonts/numbers/n6.h"
494 float const MESH_NUMBER_7
[] = {
495 #include "fonts/numbers/n7.h"
498 float const MESH_NUMBER_8
[] = {
499 #include "fonts/numbers/n8.h"
502 float const MESH_NUMBER_9
[] = {
503 #include "fonts/numbers/n9.h"
506 float const MESH_NUMBERS_BUFFER
[] =
508 #include "fonts/numbers/n0.h"
509 #include "fonts/numbers/n1.h"
510 #include "fonts/numbers/n2.h"
511 #include "fonts/numbers/n3.h"
512 #include "fonts/numbers/n4.h"
513 #include "fonts/numbers/n5.h"
514 #include "fonts/numbers/n6.h"
515 #include "fonts/numbers/n7.h"
516 #include "fonts/numbers/n8.h"
517 #include "fonts/numbers/n9.h"
520 #define MESH_NUMBER_DIVISOR 6
522 u32
const MESH_NUMBERS_OFFSETS
[][2] =
526 vg_list_size( MESH_NUMBER_0
) / MESH_NUMBER_DIVISOR
529 vg_list_size( MESH_NUMBER_0
) / MESH_NUMBER_DIVISOR
,
530 vg_list_size( MESH_NUMBER_1
) / MESH_NUMBER_DIVISOR
534 vg_list_size( MESH_NUMBER_0
) +
535 vg_list_size( MESH_NUMBER_1
)
536 ) / MESH_NUMBER_DIVISOR
,
537 vg_list_size( MESH_NUMBER_2
) / MESH_NUMBER_DIVISOR
541 vg_list_size( MESH_NUMBER_0
) +
542 vg_list_size( MESH_NUMBER_1
) +
543 vg_list_size( MESH_NUMBER_2
)
544 ) / MESH_NUMBER_DIVISOR
,
545 vg_list_size( MESH_NUMBER_3
) / MESH_NUMBER_DIVISOR
549 vg_list_size( MESH_NUMBER_0
) +
550 vg_list_size( MESH_NUMBER_1
) +
551 vg_list_size( MESH_NUMBER_2
) +
552 vg_list_size( MESH_NUMBER_3
)
553 ) / MESH_NUMBER_DIVISOR
,
554 vg_list_size( MESH_NUMBER_4
) / MESH_NUMBER_DIVISOR
558 vg_list_size( MESH_NUMBER_0
) +
559 vg_list_size( MESH_NUMBER_1
) +
560 vg_list_size( MESH_NUMBER_2
) +
561 vg_list_size( MESH_NUMBER_3
) +
562 vg_list_size( MESH_NUMBER_4
)
563 ) / MESH_NUMBER_DIVISOR
,
564 vg_list_size( MESH_NUMBER_5
) / MESH_NUMBER_DIVISOR
568 vg_list_size( MESH_NUMBER_0
) +
569 vg_list_size( MESH_NUMBER_1
) +
570 vg_list_size( MESH_NUMBER_2
) +
571 vg_list_size( MESH_NUMBER_3
) +
572 vg_list_size( MESH_NUMBER_4
) +
573 vg_list_size( MESH_NUMBER_5
)
574 ) / MESH_NUMBER_DIVISOR
,
575 vg_list_size( MESH_NUMBER_6
) / MESH_NUMBER_DIVISOR
579 vg_list_size( MESH_NUMBER_0
) +
580 vg_list_size( MESH_NUMBER_1
) +
581 vg_list_size( MESH_NUMBER_2
) +
582 vg_list_size( MESH_NUMBER_3
) +
583 vg_list_size( MESH_NUMBER_4
) +
584 vg_list_size( MESH_NUMBER_5
) +
585 vg_list_size( MESH_NUMBER_6
)
586 ) / MESH_NUMBER_DIVISOR
,
587 vg_list_size( MESH_NUMBER_7
) / MESH_NUMBER_DIVISOR
591 vg_list_size( MESH_NUMBER_0
) +
592 vg_list_size( MESH_NUMBER_1
) +
593 vg_list_size( MESH_NUMBER_2
) +
594 vg_list_size( MESH_NUMBER_3
) +
595 vg_list_size( MESH_NUMBER_4
) +
596 vg_list_size( MESH_NUMBER_5
) +
597 vg_list_size( MESH_NUMBER_6
) +
598 vg_list_size( MESH_NUMBER_7
)
599 ) / MESH_NUMBER_DIVISOR
,
600 vg_list_size( MESH_NUMBER_8
) / MESH_NUMBER_DIVISOR
604 vg_list_size( MESH_NUMBER_0
) +
605 vg_list_size( MESH_NUMBER_1
) +
606 vg_list_size( MESH_NUMBER_2
) +
607 vg_list_size( MESH_NUMBER_3
) +
608 vg_list_size( MESH_NUMBER_4
) +
609 vg_list_size( MESH_NUMBER_5
) +
610 vg_list_size( MESH_NUMBER_6
) +
611 vg_list_size( MESH_NUMBER_7
) +
612 vg_list_size( MESH_NUMBER_8
)
613 ) / MESH_NUMBER_DIVISOR
,
614 vg_list_size( MESH_NUMBER_9
) / MESH_NUMBER_DIVISOR
620 const char *map_name
;
622 const char *description
;
627 int _unlock
, _linked
; // When completed, unlock this level
628 struct cmp_level
*unlock
, *linked
;
633 SteamLeaderboard_t steam_leaderboard
;
636 static struct cmp_level cmp_levels_tutorials
[] =
641 .title
= "PRINCIPLE 1",
642 .map_name
= "cmp_t01",
643 .description
= "Utilize basic transport methods",
651 .title
= "PRINCIPLE 2",
652 .map_name
= "cmp_t02",
653 .description
= "Utilize the twisty turny(TM) piece to split\n"
654 "the marble stream into two",
662 .title
= "PRINCIPLE 3",
663 .map_name
= "cmp_t03",
664 .description
= "Merge transport into one",
672 .title
= "PRINCIPLE 4",
673 .map_name
= "cmp_t04",
674 .description
= "Some stages require multiple runs to succeed\n"
682 static struct cmp_level cmp_levels_basic
[] =
687 .title
= "SUBDIVISION 1",
688 .map_name
= "cmp_b01",
689 .description
= "Sometimes getting the desired amount takes\n"
690 "dividing up the input and recombining it.",
698 .title
= "SUBDIVISION 2",
699 .map_name
= "cmp_b02",
708 .title
= "RESTRUCTURE",
709 .map_name
= "cmp_b03",
710 .description
= "It is possible to swap these values using\n"
711 "simple division and addition.",
717 .title
= "SERIALIZE",
718 .map_name
= "cmp_b04",
719 .description
= "Merge and sort",
725 .title
= "PATTERNS 1",
726 .map_name
= "cmp_b05",
727 .description
= "Replicate",
733 .title
= "PATTERNS 2",
734 .map_name
= "cmp_b06",
735 .description
= "Replicate MORE",
741 .title
= "MIGHTY CONSUMER",
742 .map_name
= "cmp_b07",
743 .description
= "Build a greedy system",
750 .title
= "ENCRYPTED 1",
751 .map_name
= "cmp_b08",
752 .description
= "Some configurations may not be valid",
759 .map_name
= "cmp_b09",
760 .description
= "Reverse the incoming order. Always length 4",
767 .title
= "PRINCIPLE 5",
768 .map_name
= "cmp_b10",
770 "The eager engineers among you may have already spotted\n"
771 "and utilized these parts of the system\n"
773 "We forgot to include the relevant principle tasks as\n"
774 "of your training package, you will now be tasked to\n"
783 .title
= "ROUTING PROBLEM",
784 .map_name
= "cmp_routing",
786 "Things can get a little chaotic on tight boards, do your\n"
787 "best to utilize principle 5 to get the job done\n",
793 .title
= "PRINCIPLE 6",
794 .map_name
= "cmp_b11",
796 "While hovering over a simple tile peice, right click and\n"
797 "drag to start creating a wire. These can be connected to\n"
798 "the left, or right recieving pins of a Twisty Turny(TM).\n"
800 "Once connected, the Twisty Turny(TM) will no longer\n"
801 "'flip flop' as marbles run through them, but instead be\n"
802 "et to left or right rotating only. As indicated by the\n"
803 "status arrow beneath them\n"
805 "When the left or right slot is triggered, the Twisty\n"
806 "Turny(TM) will switch modes according to that input.\n"
808 "Trigger wires apply instantaneously, however if both the\n"
809 "left and right inputs are recieved at the same time,\n"
810 "this results in no operation being performed, and no\n"
811 "state changes take place in the Twisty Turny(TM)\n",
819 .map_name
= "cmp_not",
821 "Test your knowledge of triggers, build an 'NOT GATE'\n"
822 "emulated by marble logic.",
830 .map_name
= "cmp_and",
832 "A slightly more complicated gate, but shouldn't be\n"
833 "too difficult for your skillset.",
839 .title
= "QUALIFICATION PROJECT",
840 .map_name
= "cmp_grad",
842 "There's no instructions here, resolve and complete this\n"
843 "task to qualify yourself as an official marble engineer",
848 static struct cmp_level cmp_levels_grad
[] =
853 .map_name
= "cmp_i01",
855 "Device a scheme to filter and sort the inputs. If you\n"
856 "believe you lack the tools required to solve this one,\n"
857 "take a harder look at the inputs.",
864 .map_name
= "cmp_i02",
866 "Split the inputs up into a third of their values\n"
868 "Is this possible? -HG",
875 .map_name
= "cmp_xor",
877 "Significantly more complicated than an AND or NOT gate,\n"
883 .title
= "SECRET CODE",
884 .map_name
= "cmp_secret",
886 "Only one input should send an unlock signal marble to\n"
892 #define NUM_CAMPAIGN_LEVELS (vg_list_size( cmp_levels_tutorials ) + vg_list_size( cmp_levels_basic ) + vg_list_size( cmp_levels_grad ))
902 static struct serializable_set
904 struct cmp_level
*pack
;
907 career_serializable
[] =
910 .pack
= cmp_levels_tutorials
,
911 .count
= vg_list_size( cmp_levels_tutorials
)
914 .pack
= cmp_levels_basic
,
915 .count
= vg_list_size( cmp_levels_basic
)
918 .pack
= cmp_levels_grad
,
919 .count
= vg_list_size( cmp_levels_grad
)
923 // Setup pointers and that
924 static void career_local_data_init(void)
926 struct cmp_level
*level_ptrs
[ NUM_CAMPAIGN_LEVELS
];
929 for( int i
= 0; i
< vg_list_size( career_serializable
); i
++ )
931 struct serializable_set
*set
= &career_serializable
[i
];
933 for( int j
= 0; j
< set
->count
; j
++ )
934 level_ptrs
[ set
->pack
[j
].serial_id
] = &set
->pack
[j
];
938 for( int i
= 0; i
< vg_list_size( career_serializable
); i
++ )
940 struct serializable_set
*set
= &career_serializable
[i
];
942 for( int j
= 0; j
< set
->count
; j
++ )
944 struct cmp_level
*lvl
= &set
->pack
[j
];
945 lvl
->unlock
= lvl
->_unlock
? level_ptrs
[ lvl
->_unlock
]: NULL
;
946 lvl
->linked
= lvl
->_linked
? level_ptrs
[ lvl
->_linked
]: NULL
;