organise level information
[fishladder.git] / fishladder_resources.h
1 // TEXTURES
2 // ===========================================================================================================
3
4 vg_tex2d tex_tile_data = { .path = "textures/tileset.qoi" };
5 vg_tex2d tex_tile_detail = { .path = "textures/tile_overlays.qoi" };
6
7 vg_tex2d tex_tiles_wood = { .path = "textures/tile_wood.qoi" };
8 vg_tex2d tex_tiles_min = { .path = "textures/tile_minimal.qoi" };
9 vg_tex2d tex_tiles_lab = { .path = "textures/tile_lab.qoi" };
10
11 vg_tex2d tex_ball_noise = { .path = "textures/bnoise.qoi" };
12 vg_tex2d tex_monofur = { .path = "textures/ascii.qoi", .flags = VG_TEXTURE_NO_MIP };
13 vg_tex2d tex_unkown = { .path = "textures/unkown.qoi" };
14 vg_tex2d tex_buttons = { .path = "textures/buttons.qoi" };
15 vg_tex2d tex_sprites = { .path = "textures/autocombine.qoi" };
16
17 vg_tex2d *texture_list[] = {
18 &tex_tile_detail,
19 &tex_tile_data,
20 &tex_tiles_wood,
21 &tex_tiles_min,
22 &tex_tiles_lab,
23 &tex_ball_noise,
24 &tex_monofur,
25 &tex_unkown,
26 &tex_buttons,
27 &tex_sprites
28 };
29
30 #include "sprites_autocombine.h"
31
32 // AUDIO
33 // ===========================================================================================================
34
35 sfx_vol_control audio_volume_sfx = { .val = 1.0f, .name = "Sound effects" };
36 sfx_vol_control audio_volume_music = { .val = 1.0f, .name = "Music" };
37
38 sfx_system audio_system_sfx =
39 {
40 .vol = 1.f,
41 .ch = 1,
42 .vol_src = &audio_volume_sfx,
43 .name = "sfx"
44 };
45
46 sfx_set audio_tile_mod =
47 {
48 .sources = "\
49 sound/mod_01.ogg\0\
50 sound/mod_02.ogg\0\
51 sound/mod_03.ogg\0\
52 sound/mod_04.ogg\0\
53 sound/mod_05.ogg\0\
54 sound/mod_06.ogg\0",
55 .flags = 0
56 };
57
58 sfx_set audio_splitter =
59 {
60 .sources = "\
61 sound/splitter_01.ogg\0"
62 };
63
64 sfx_set audio_rolls =
65 {
66 .sources = "\
67 sound/rolling_01.ogg\0\
68 sound/rolling_02.ogg\0"
69 };
70
71 sfx_set audio_random =
72 {
73 .sources = "\
74 sound/random_01.ogg\0\
75 sound/random_02.ogg\0\
76 sound/random_03.ogg\0\
77 sound/random_04.ogg\0\
78 sound/random_05.ogg\0\
79 sound/random_06.ogg\0\
80 sound/random_07.ogg\0\
81 sound/random_08.ogg\0"
82 };
83
84 sfx_set audio_clicks =
85 {
86 .sources = "\
87 sound/click_a.ogg\0\
88 sound/click_b.ogg\0\
89 sound/click_c.ogg\0"
90 };
91
92 sfx_set audio_tones =
93 {
94 .sources = "\
95 sound/y0.ogg\0\
96 sound/y1.ogg\0\
97 sound/y2.ogg\0\
98 sound/y3.ogg\0\
99 sound/y4.ogg\0\
100 sound/y5.ogg\0\
101 sound/y6.ogg\0\
102 sound/y7.ogg\0\
103 sound/y8.ogg\0\
104 sound/win.ogg\0"
105 };
106
107 // One two or three layers of rolling noise
108 sfx_system audio_system_balls_rolling =
109 {
110 .vol = 0.7f, .ch = 1, .vol_src = &audio_volume_sfx,
111 .name = "Balls Rolling", .flags = SFX_FLAG_REPEAT | SFX_FLAG_PERSISTENT
112 };
113
114 // Various oneshots
115 sfx_system audio_system_balls_switching =
116 {
117 .vol = 0.2f, .ch = 1, .vol_src = &audio_volume_sfx,
118 .name = "Balls Switching"
119 };
120
121 // Gameplay critical sounds eg. splitter sound rocking
122 sfx_system audio_system_balls_important =
123 {
124 .vol = 1.f, .ch = 1, .vol_src = &audio_volume_sfx,
125 .name = "Balls Gameplay"
126 };
127
128 // Suplemental sounds
129 sfx_system audio_system_balls_extra =
130 {
131 .vol = 0.27f, .ch = 1, .vol_src = &audio_volume_sfx,
132 .name = "Balls Extra"
133 };
134
135 sfx_system audio_system_ui =
136 {
137 .vol = 1.f, .ch = 1, .vol_src = &audio_volume_sfx,
138 .name = "UI"
139 };
140
141 static void resource_load_main(void)
142 {
143 // Textures // UI
144 vg_tex2d_init( texture_list, vg_list_size( texture_list ) );
145
146 // Audio
147 sfx_set_init( &audio_tile_mod, NULL );
148 sfx_set_init( &audio_splitter, NULL );
149 sfx_set_init( &audio_rolls, NULL );
150 sfx_set_init( &audio_random, NULL );
151 sfx_set_init( &audio_clicks, NULL );
152 sfx_set_init( &audio_tones, NULL );
153 }
154
155 static void resource_free_main(void)
156 {
157 vg_tex2d_free( texture_list, vg_list_size( texture_list ) );
158
159 sfx_set_free( &audio_tile_mod );
160 sfx_set_free( &audio_splitter );
161 sfx_set_free( &audio_rolls );
162 sfx_set_free( &audio_random );
163 sfx_set_free( &audio_clicks );
164 sfx_set_free( &audio_tones );
165 }
166
167 // SHADERS
168 // ===========================================================================================================
169
170 SHADER_DEFINE( shader_tile_colour,
171
172 // VERTEX
173 "layout (location=0) in vec2 a_co;"
174 "uniform mat3 uPv;"
175 "uniform vec3 uOffset;"
176 ""
177 "void main()"
178 "{"
179 "gl_Position = vec4( uPv * vec3( a_co * uOffset.z + uOffset.xy, 1.0 ), 1.0 );"
180 "}",
181
182 // FRAGMENT
183 "out vec4 FragColor;"
184 "uniform vec4 uColour;"
185 ""
186 "void main()"
187 "{"
188 "FragColor = uColour;"
189 "}"
190 ,
191 UNIFORMS({ "uPv", "uOffset", "uColour" })
192 )
193
194 SHADER_DEFINE( shader_ball,
195 // VERTEX
196 "layout (location=0) in vec2 a_co;"
197 "uniform vec3 uOffset;"
198 "uniform mat3 uPv;"
199 ""
200 "out vec4 aTexCoords;"
201 ""
202 "void main()"
203 "{"
204 // Vertex transform
205 "vec3 worldpos = vec3( (a_co * 0.5 - 0.25) * uOffset.z + uOffset.xy, 1.0 );"
206 "gl_Position = vec4( uPv * worldpos, 1.0 );"
207
208 // Create texture coords
209 "aTexCoords = vec4( a_co, worldpos.xy );"
210 "}",
211
212 // FRAGMENT
213 "out vec4 FragColor;"
214 ""
215 "uniform sampler2D uTexMain;"
216 "uniform vec3 uColour;"
217 "uniform vec2 uTexOffset;"
218 ""
219 "in vec4 aTexCoords;"
220 ""
221 "void main()"
222 "{"
223 "vec2 center_coords = aTexCoords.xy - 0.5;"
224 "vec2 center_coords_sqr = center_coords*center_coords;"
225 "float circle_factor = smoothstep( 0.07, 0.0625, center_coords_sqr.x+center_coords_sqr.y );"
226
227 "float bulge_amt = center_coords_sqr.x+center_coords_sqr.y;"
228 "vec2 warped_coords = aTexCoords.zw+uTexOffset - center_coords;"
229 "vec4 noise_sample = texture( uTexMain, warped_coords );"
230
231 "float rim_light = (center_coords_sqr.x+center_coords_sqr.y)*15.0;"
232
233 "vec2 shadow_coords = center_coords + vec2(0.02,0.07);"
234 "vec2 shadow_coords_sqr = shadow_coords*shadow_coords;"
235 "float shadow = exp(-((shadow_coords_sqr.x+shadow_coords_sqr.y)-0.0125)*15.0);"
236
237 "vec3 marble_comp = uColour*0.9 + (noise_sample.x*0.7+pow(rim_light,3.0)*2.0) * 0.1;"
238 //"vec4 colour_comp = mix( vec4(0.74,0.53,0.34,shadow), vec4(marble_comp,1.0), circle_factor );"
239 "vec4 colour_comp = mix( vec4(0.2,0.2,0.2,shadow), vec4(marble_comp,1.0), circle_factor );"
240
241 "FragColor = colour_comp;"
242 "}"
243 ,
244 UNIFORMS({ "uTexMain", "uColour", "uOffset", "uPv", "uTexOffset" })
245 )
246
247 SHADER_DEFINE( shader_tile_main,
248 // VERTEX
249 "layout (location=0) in vec2 a_co;"
250 "uniform vec4 uOffset;" // Tile x/y, uv x/y
251 "uniform mat3 uPv;"
252 "uniform mat2 uSubTransform;"
253 "uniform float uVisibility;"
254 ""
255 "out vec4 aTexCoords;"
256 "out vec2 aWorldCoords;"
257 ""
258 "vec2 hash22(vec2 p)"
259 "{"
260 "vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));"
261 "p3 += dot(p3, p3.yzx+33.33);"
262 "return fract((p3.xx+p3.yz)*p3.zy);"
263 "}"
264 ""
265 "void main()"
266 "{"
267 "vec2 hash_val = hash22(uOffset.xy);"
268 "float scaling_factor = smoothstep( hash_val.x, hash_val.x+1.0, uVisibility );"
269
270 // Vertex transform
271 "vec2 subtransform = uSubTransform * (a_co-0.5) * scaling_factor + 0.5;"
272 "vec3 worldpos = vec3( subtransform + uOffset.xy, 1.0 );"
273 "gl_Position = vec4( uPv * worldpos, 1.0 );"
274
275 // Create texture coords
276 "vec2 random_offset = floor(hash_val * 4.0) * 0.25;"
277 "vec2 edge_safe_coords = a_co * 0.98 + 0.01;"
278 "aTexCoords = vec4((edge_safe_coords + uOffset.zw) * 0.25, edge_safe_coords * 0.25 + random_offset );"
279 "aWorldCoords = worldpos.xy;"
280 "}",
281
282 // FRAGMENT
283 "out vec4 FragColor;"
284 ""
285 "uniform sampler2D uTexGlyphs;"
286 "uniform sampler2D uTexWood;"
287 "uniform float uGhost;"
288 "uniform float uForeground;"
289 "uniform vec2 uMousePos;"
290 "uniform vec4 uColour;"
291 "uniform vec3 uShadowing;"
292 ""
293 "in vec4 aTexCoords;"
294 "in vec2 aWorldCoords;"
295 ""
296 "void main()"
297 "{"
298 //"vec3 shadowing_colour = vec3( 0.93, 0.88536, 0.8184 ) * 0.97;"
299 //"vec3 shadowing_colour = vec3( 0.8, 0.8, 0.8 );"
300
301 "vec4 glyph = texture( uTexGlyphs, aTexCoords.xy );"
302 "vec4 wood = texture( uTexWood, aTexCoords.zw );"
303 "vec4 wood_secondary = texture( uTexWood, aTexCoords.zw + 0.25 );"
304 "vec3 wood_comp = mix( wood_secondary.rgb * uShadowing, wood.rgb, clamp( glyph.b*2.0-1.0, 0.0, 1.0 ) );"
305
306 //"vec3 shadows = mix( vec3( 0.85, 0.7344, 0.561 ), vec3(1.0,1.0,1.0), glyph.r );"
307 "vec3 shadows = mix( uShadowing, vec3(1.0,1.0,1.0), glyph.r );"
308
309 "vec4 output_regular = vec4( wood_comp * shadows, mix( glyph.a, glyph.b, uForeground ) );"
310
311 "float ghost_dist = clamp( 1.5 - distance(uMousePos, aWorldCoords), 0.0, 1.0 );"
312 "vec4 output_ghost = vec4( 1.0, 1.0, 1.0, glyph.g * ghost_dist );"
313
314 "FragColor = mix( output_regular, output_ghost, uGhost ) * uColour;"
315 "}"
316 ,
317 UNIFORMS({ "uPv", "uOffset", "uTexGlyphs", "uTexWood", "uSubTransform", "uGhost", "uMousePos",
318 "uColour", "uForeground", "uVisibility", "uShadowing" })
319 )
320
321 SHADER_DEFINE( shader_background,
322 // VERTEX
323 "layout (location=0) in vec2 a_co;"
324 "uniform mat3 uPv;"
325 "uniform vec3 uOffset;"
326 ""
327 "out vec2 aTexCoords;"
328 ""
329 "void main()"
330 "{"
331 "vec2 world_pos = a_co * uOffset.z + uOffset.xy;"
332 "gl_Position = vec4( uPv * vec3( world_pos, 1.0 ), 1.0 );"
333 "aTexCoords = a_co;"
334 "}",
335
336 // FRAGMENT
337 "out vec4 FragColor;"
338 ""
339 "uniform sampler2D uTexMain;"
340 "uniform sampler2D uSamplerNoise;"
341 "uniform float uVariance;"
342 "uniform float uVisibility;"
343 ""
344 "in vec2 aTexCoords;"
345 ""
346 "void main()"
347 "{"
348 "float ao_accum = 0.0;"
349 "for( int i=0; i<10; ++i )"
350 "{"
351 "vec2 random_noise = (texture( uSamplerNoise, aTexCoords * 20.0 + float(i) * 0.2 ).xy - vec2( 0.5, 0.5 )) * uVariance;"
352 "vec4 background = texture( uTexMain, aTexCoords + random_noise );"
353 "ao_accum += background.r * clamp((1.0 - length( random_noise )), 0.0, 1.0);"
354 "}"
355 "ao_accum *= 0.15;"
356
357 "vec4 data_this_tile = texture( uTexMain, aTexCoords );"
358
359 "ao_accum -= data_this_tile.r;"
360 "ao_accum *= uVisibility;"
361
362 "vec3 colour_main = mix( vec3( 0.369768, 0.3654, 0.42 ), vec3( 0.275, 0.388, 0.553 ), data_this_tile.g * uVisibility );"
363
364 "vec2 square_coords = fract( aTexCoords * 64.0 );"
365 "vec2 grid_coords = abs( square_coords - 0.5 );"
366 "float edge_contrast = (1.0-ao_accum*0.2);"
367
368 "float gridline = step( 0.49, max(grid_coords.x,grid_coords.y) );"
369 "float gridline_fadeout = min(max(edge_contrast-1.0, 0.0)*40.0 + data_this_tile.g,10.0);"
370
371 "FragColor = vec4( colour_main * edge_contrast + gridline * 0.02 * gridline_fadeout, 1.0 );"
372 "}"
373 ,
374 UNIFORMS({ "uPv", "uOffset", "uTexMain", "uVariance", "uSamplerNoise", "uVisibility" })
375 )
376
377 SHADER_DEFINE( shader_wire,
378 // VERTEX
379 "layout (location=0) in vec2 a_co;"
380 "uniform vec3 uStart;"
381 "uniform vec3 uEnd;"
382 "uniform mat3 uPv;"
383 "uniform float uCurve;"
384 ""
385 "out vec2 aTexCoords;"
386 ""
387 "vec3 sample_curve_time( float t )"
388 "{"
389 "vec3 line_coord = mix( uStart, uEnd, t );"
390
391 "float curve_amt = 1.0-(pow((t*2.0-1.0),2.0));"
392 "return vec3( line_coord.x, line_coord.y - curve_amt*uCurve, line_coord.z );"
393 "}"
394 ""
395 "void main()"
396 "{"
397 // Vertex transform
398 "vec3 p0 = sample_curve_time( a_co.x );"
399 "vec3 p1 = sample_curve_time( a_co.x + 0.025 );"
400
401 "vec2 line_tangent = normalize(p1.xy-p0.xy);"
402 "vec2 line_normal = vec2( -line_tangent.y, line_tangent.x );"
403
404 "vec2 worldfinal = p0.xy + line_normal*a_co.y*p0.z;"
405
406 "gl_Position = vec4( uPv * vec3(worldfinal, 1.0), 1.0 );"
407
408 // Create texture coords (todo: include stretch adjusted coords?)
409 "aTexCoords = vec2( a_co.x, a_co.y + 0.5 );"
410 "}",
411
412 // FRAGMENT
413 "out vec4 FragColor;"
414 ""
415 "uniform sampler2D uTexMain;"
416 "uniform vec4 uColour;"
417 "uniform float uTime;"
418 "uniform float uGlow;"
419 ""
420 "in vec2 aTexCoords;"
421 ""
422 "void main()"
423 "{"
424 // Compute shadowing
425 "float shadow = 1.0 - abs(aTexCoords.y - 0.5) * 2.0;"
426 "float masking = smoothstep( 0.5, 0.8, shadow );"
427
428 "vec3 colour_comp = mix( vec3(0.0,0.0,0.0), uColour.rgb, masking );"
429
430 "float flow_thing = fract( aTexCoords.x + uTime );"
431 "vec3 final_comp = colour_comp + flow_thing * uGlow;"
432
433 "FragColor = vec4( final_comp, max( shadow* 0.2, masking ) * uColour.a );"
434 "}"
435 ,
436 UNIFORMS({ "uPv", "uColour", "uTexMain", "uStart", "uEnd", "uCurve", "uTime", "uGlow" })
437 )
438
439 SHADER_DEFINE( shader_buttons,
440 // VERTEX
441 "layout (location=0) in vec2 a_co;"
442 "uniform vec4 uOffset;" // Tile x/y, uv x/y
443 "uniform mat3 uPv;"
444 ""
445 "out vec2 aTexCoords;"
446 ""
447 "void main()"
448 "{"
449 // Vertex transform
450 "vec3 worldpos = vec3( a_co + uOffset.xy, 1.0 );"
451 "gl_Position = vec4( uPv * worldpos, 1.0 );"
452
453 // Create texture coords
454 "vec2 edge_safe_coords = a_co * 0.98 + 0.01;"
455 "aTexCoords = (edge_safe_coords + uOffset.zw) * 0.25;"
456 "}",
457
458 // FRAGMENT
459 "out vec4 FragColor;"
460 ""
461 "uniform sampler2D uTexMain;"
462 "uniform vec4 uColour;" // rgb, light amount
463 ""
464 "in vec2 aTexCoords;"
465 ""
466 "void main()"
467 "{"
468 "vec4 glyph = texture( uTexMain, aTexCoords.xy );"
469
470 "FragColor = vec4( uColour.rgb * (mix(glyph.r, glyph.g, uColour.a)+0.02)*2.6 + glyph.b * 0.4, glyph.a );"
471 "}"
472 ,
473 UNIFORMS({ "uPv", "uOffset", "uTexMain", "uColour" })
474 )
475
476 SHADER_DEFINE( shader_sprite,
477
478 // VERTEX
479 "layout (location=0) in vec2 a_co;" // quad mesh
480 "uniform vec4 uUv;"
481 "uniform vec3 uPos;"
482 ""
483 "uniform mat3 uPv;"
484 ""
485 "out vec2 aTexCoords;"
486 ""
487 "void main()"
488 "{"
489 "vec2 vertex_world = uUv.zw * (a_co-0.5) * uPos.z + uPos.xy;"
490 "gl_Position = vec4( uPv * vec3( vertex_world, 1.0 ), 1.0 );"
491 "aTexCoords = uUv.xy + a_co*uUv.zw;"
492 "}",
493
494 // FRAGMENT
495 "uniform sampler2D uTexMain;"
496 "out vec4 FragColor;"
497 ""
498 "in vec2 aTexCoords;"
499 ""
500 "void main()"
501 "{"
502 "vec4 texture_sample = texture( uTexMain, aTexCoords );"
503 "FragColor = texture_sample;"
504 "}"
505 ,
506 UNIFORMS({ "uPv", "uTexMain", "uUv", "uPos" })
507 )
508
509 void vg_register(void)
510 {
511 SHADER_INIT( shader_tile_colour );
512 SHADER_INIT( shader_tile_main );
513 SHADER_INIT( shader_ball );
514 SHADER_INIT( shader_background );
515 SHADER_INIT( shader_wire );
516 SHADER_INIT( shader_buttons );
517 SHADER_INIT( shader_sprite );
518 }
519
520 /*
521 0000 0 | 0001 1 | 0010 2 | 0011 3
522 | | | | |
523 X | X= | X | X=
524 | | |
525 0100 4 | 0101 5 | 0110 6 | 0111 7
526 | | | | |
527 =X | =X= | =X | =X=
528 | | |
529 1000 8 | 1001 9 | 1010 10 | 1011 11
530 | | | | |
531 X | X= | X | X=
532 | | | | | | |
533 1100 12 | 1101 13 | 1110 14 | 1111 15
534 | | | | |
535 =X | =X= | =X | =X=
536 | | | | | | |
537 */
538
539 struct cmp_level
540 {
541 // Basic info
542 int serial_id;
543
544 const char *map_name;
545 const char *title;
546 const char *description;
547
548 const char *achievement;
549
550 int _unlock, _linked; // When completed, unlock this level
551 int is_tutorial;
552
553 // Aesthetic
554 struct world_string
555 {
556 enum placement
557 {
558 k_placement_top,
559 k_placement_bottom
560 }
561 placement;
562
563 const char *str;
564 }
565 strings[2];
566
567 // Persistent stats
568 int unlocked;
569 int completed_score;
570
571 // Runtime
572 struct world_button btn;
573 struct cmp_level *unlock, *linked;
574
575 #ifdef VG_STEAM
576 SteamLeaderboard_t steam_leaderboard;
577 #endif
578 };
579
580 static struct cmp_level cmp_levels_tutorials[] =
581 {
582 {
583 0, "cmp_t01", "PRINCIPLE 1", "",
584 ._unlock = 1,
585 .is_tutorial = 1
586 },
587 {
588 1, "cmp_t02", "PRINCIPLE 2", "",
589 ._unlock = 2,
590 .is_tutorial = 1,
591 },
592 {
593 2, "cmp_t03", "PRINCIPLE 3", "",
594 ._unlock = 12,
595 .is_tutorial = 1
596 },
597 {
598 12, "cmp_t04", "PRINCIPLE 4", "",
599 ._unlock = 6,
600 .is_tutorial = 1,
601 .achievement = "TUTORIALS"
602 },
603 {
604 15, "cmp_b10", "PRINCIPLE 5", "",
605 ._unlock = 16,
606 .is_tutorial = 1
607 },
608 {
609 17, "cmp_b11", "PRINCIPLE 6", "(Right click)",
610 ._unlock = 18,
611 .is_tutorial = 1
612 },
613 {
614 26, "cmp_p7", "PRINCIPLE 7", "Emitters",
615 ._unlock = 27,
616 .is_tutorial = 1
617 }
618 };
619
620 static struct cmp_level cmp_levels_basic[] =
621 {
622 {
623 6, "cmp_b04", "PATCH", "",
624 ._unlock = 7,
625 ._linked = 3
626 },
627 {
628 3, "cmp_b01", "SUBDIVISION 1", "",
629 ._linked = 4,
630 ._unlock = 5
631 },
632 {
633 4, "cmp_b02", "SUBDIVISION 2", "",
634 ._unlock = 7
635 },
636 {
637 5, "cmp_b03", "RESTRUCTURE", "",
638 ._unlock = 8
639 },
640 {
641 7, "cmp_b05", "PATTERNS 1", "",
642 ._unlock = 15,
643 ._linked = 8
644 },
645 {
646 8, "cmp_b06", "PATTERNS 2", "",
647 ._unlock = 15
648 },
649 {
650 16, "cmp_routing", "ROUTING PROBLEM", "",
651 ._linked = 9
652 },
653 {
654 9, "cmp_b07", "MIGHTY CONSUMER", "",
655 ._linked = 10,
656 ._unlock = 11,
657 .achievement = "MIGHTY_CONSUMER"
658 },
659 {
660 10, "cmp_b08", "SHIFT", "",
661 ._unlock = 17
662 },
663 {
664 11, "cmp_b09", "REVERSE", "",
665 ._unlock = 17
666 },
667 {
668 18, "cmp_not", "NOT GATE", "",
669 ._linked = 19,
670 ._unlock = 20
671 },
672 {
673 19, "cmp_and", "AND GATE", "",
674 ._unlock = 20
675 },
676 {
677 20, "cmp_xor", "QUALIFICATION PROJECT", "",
678 ._unlock = 25,
679 .achievement = "GRADUATE"
680 },
681 {
682 27, "cmp_expander", "EXPAND", "",
683 ._unlock = 28
684 },
685 {
686 28, "cmp_pattern3", "PATTERNS 3", "",
687 ._linked = 29
688 },
689 {
690 29, "cmp_routing2", "ROUTING PROBLEM 2", "Spaghetti!",
691 ._linked = 30
692 },
693 {
694 30, "cmp_exact5", "EXACTLY 5", ""
695 }
696 };
697
698 static struct cmp_level cmp_levels_grad[] =
699 {
700 {
701 13, "cmp_i01", "SORT", "",
702 ._linked = 14
703 },
704 {
705 14, "cmp_i02", "THIRDS", "",
706 ._linked = 21
707 },
708 {
709 21, "cmp_grad", "SIMPLE ADDITION", "",
710 ._linked = 22,
711 ._unlock = 23
712 },
713 {
714 22, "cmp_secret", "SECRET CODE", "",
715 ._unlock = 23
716 }
717 };
718
719 static struct cmp_level cmp_levels_computer[] =
720 {
721 {
722 23, "cmp_binary", "3 BIT BINARY", "Convert amount to binary",
723 ._unlock = 24,
724 .strings =
725 {
726 {
727 .placement = k_placement_bottom,
728 .str =
729 "\t\t\t\t\t\t\t\t\t\t\x83 \x84\n"
730 "\t\t\t\t\t\t\t\t\t\t\x83 \x84 Binary\n"
731 "\t\t\t\t\t\t\t\t\t\t\x83 4 2 1 \x84"
732 },
733 {
734 .placement = k_placement_top,
735 .str =
736 "\n"
737 "\t\t\t\t\t\t\t\t\t\t\t Count"
738 }
739 }
740 },
741 {
742 24, "cmp_add3b", "3 BIT ADDER", "Binary addition",
743 ._unlock = 25,
744 .strings =
745 {
746 {
747 .placement = k_placement_top,
748 //.str ="\t\t\t\t\t\t\t\t\t| NUMBER A | | NUMBER B |\n"
749 .str =""
750 "\t\t\t\t\t\t\t\t\t\x8A 4 2 1 \x8B \x8A 4 2 1 \x8B\n"
751 "\t\t\t\t\t\t\t\t\t\x83 \x84 add \x83 \x84\n"
752 "\t\t\t\t\t\t\t\t\t\x83 \x84 \x83 \x84"
753 },
754 {
755 .placement = k_placement_bottom,
756 .str =
757 "\t\t\t\x83 \x84\n"
758 "\t\t\t\x83 \x84 result a+b\n"
759 "\t\t\t\x83 8 4 2 1 \x84"
760 }
761 }
762 },
763 {
764 25, "cmp_plot3x3", "3x3 PLOT", "2 bit x/y",
765 .strings =
766 {
767 {
768 .placement = k_placement_top,
769 .str=
770 "\t\t\t\t\t\t\t\t\x8A 2 1 \x8B \x8A 2 1 \x8B\n"
771 "\t\t\t\t\t\t\t\t\x83 \x84 X Y \x83 \x84\n"
772 "\t\t\t\t\t\t\t\t\x83 \x84 \x83 \x84"
773 }
774 }
775 }
776 };
777
778 #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 ) )
779
780 static struct career_level_pack
781 {
782 struct cmp_level *pack;
783 int count;
784
785 v3f primary_colour;
786 v2i origin;
787 v2i dims;
788 }
789 career_packs[] =
790 {
791 {
792 .pack = cmp_levels_tutorials,
793 .count = vg_list_size( cmp_levels_tutorials ),
794 .primary_colour = { 0.204f, 0.345f, 0.553f },
795 .origin = { -5, -2 },
796 .dims = { 1, 7 }
797 },
798 {
799 .pack = cmp_levels_basic,
800 .count = vg_list_size( cmp_levels_basic ),
801 .primary_colour = { 0.304f, 0.245f, 0.553f },
802 .origin = { -3, -2 },
803 .dims = { 3, 7 }
804 },
805 {
806 .pack = cmp_levels_grad,
807 .count = vg_list_size( cmp_levels_grad ),
808 .primary_colour = { 0.553f, 0.345f, 0.204f },
809 .origin = { -5, 6 },
810 .dims = { 5, 1 }
811 },
812 {
813 .pack = cmp_levels_computer,
814 .count = vg_list_size( cmp_levels_computer ),
815 .primary_colour = { 0.75f, 0.23f, 0.39f },
816 .origin = { -5, 8 },
817 .dims = { 5, 2 }
818 }
819 };
820
821 // Setup pointers and that
822 static void career_local_data_init(void)
823 {
824 struct cmp_level *level_ptrs[ NUM_CAMPAIGN_LEVELS ];
825 for( int i = 0; i < NUM_CAMPAIGN_LEVELS; i ++ )
826 level_ptrs[i] = NULL;
827
828 // COllect pointers
829 for( int i = 0; i < vg_list_size( career_packs ); i ++ )
830 {
831 struct career_level_pack *set = &career_packs[i];
832
833 for( int j = 0; j < set->count; j ++ )
834 {
835 int id = set->pack[j].serial_id;
836
837 if( level_ptrs[ id ] )
838 vg_error( "Serial id %u already used!\n", id );
839 else
840 level_ptrs[ set->pack[j].serial_id ] = &set->pack[j];
841 }
842 }
843
844 // Apply
845 for( int i = 0; i < vg_list_size( career_packs ); i ++ )
846 {
847 struct career_level_pack *set = &career_packs[i];
848
849 for( int j = 0; j < set->count; j ++ )
850 {
851 struct cmp_level *lvl = &set->pack[j];
852
853 if( lvl->_unlock >= NUM_CAMPAIGN_LEVELS ||
854 lvl->_linked >= NUM_CAMPAIGN_LEVELS )
855 {
856 vg_error( "_unlock / _linked out of range (%d, %d)\n",
857 lvl->_unlock, lvl->_linked );
858 }
859 else
860 {
861 lvl->unlock = lvl->_unlock? level_ptrs[ lvl->_unlock ]: NULL;
862 lvl->linked = lvl->_linked? level_ptrs[ lvl->_linked ]: NULL;
863 }
864 }
865 }
866 }