speed button
[fishladder.git] / fishladder_resources.h
1 // FONTS
2
3 struct sdf_char
4 {
5 u16 uvx, uvy, originX, originY, w, h, advance;
6 };
7
8 struct sdf_font
9 {
10 const char *name;
11 int size, width, height;
12 struct sdf_char *characters;
13 };
14
15 static struct sdf_char characters_Ubuntu[] = {
16 {655, 167, 9, 9, 18, 18, 11},
17 {561, 64, 6, 42, 25, 52, 13},
18 {435, 167, 6, 45, 32, 30, 20},
19 {797, 64, 7, 42, 46, 51, 32},
20 {362, 0, 6, 46, 39, 60, 27},
21 {918, 0, 7, 43, 55, 52, 41},
22 {973, 0, 7, 43, 47, 52, 32},
23 {467, 167, 6, 45, 23, 30, 11},
24 {142, 0, 5, 46, 30, 64, 15},
25 {172, 0, 9, 46, 30, 64, 15},
26 {291, 167, 7, 42, 38, 37, 23},
27 {171, 167, 6, 35, 40, 42, 27},
28 {410, 167, 7, 14, 25, 31, 12},
29 {625, 167, 8, 26, 30, 22, 14},
30 {558, 167, 6, 15, 25, 24, 12},
31 {0, 0, 10, 46, 39, 64, 18},
32 {88, 64, 7, 43, 41, 52, 27},
33 {532, 116, 5, 42, 32, 51, 27},
34 {370, 64, 6, 43, 39, 52, 27},
35 {409, 64, 6, 43, 39, 52, 27},
36 {176, 116, 7, 42, 42, 51, 27},
37 {448, 64, 6, 42, 39, 52, 27},
38 {170, 64, 6, 42, 40, 52, 27},
39 {343, 116, 6, 42, 40, 51, 27},
40 {854, 0, 6, 43, 40, 53, 27},
41 {210, 64, 7, 43, 40, 52, 27},
42 {146, 167, 6, 34, 25, 43, 12},
43 {564, 116, 7, 34, 26, 51, 12},
44 {211, 167, 6, 34, 40, 39, 27},
45 {370, 167, 6, 30, 40, 32, 27},
46 {251, 167, 6, 34, 40, 39, 27},
47 {525, 64, 8, 43, 36, 52, 19},
48 {401, 0, 6, 43, 57, 59, 45},
49 {700, 64, 9, 42, 49, 51, 32},
50 {218, 116, 5, 42, 42, 51, 31},
51 {769, 0, 6, 43, 44, 53, 30},
52 {935, 64, 5, 42, 45, 51, 34},
53 {383, 116, 5, 42, 40, 51, 27},
54 {423, 116, 5, 42, 38, 51, 26},
55 {724, 0, 6, 43, 45, 53, 32},
56 {45, 116, 5, 42, 44, 51, 34},
57 {590, 116, 5, 42, 23, 51, 13},
58 {487, 64, 9, 42, 38, 52, 24},
59 {89, 116, 5, 42, 44, 51, 30},
60 {461, 116, 5, 42, 38, 51, 25},
61 {646, 64, 6, 42, 54, 51, 42},
62 {0, 116, 5, 42, 45, 51, 35},
63 {674, 0, 6, 43, 50, 53, 37},
64 {302, 116, 5, 42, 41, 51, 29},
65 {312, 0, 6, 43, 50, 61, 37},
66 {133, 116, 5, 42, 43, 51, 30},
67 {813, 0, 7, 43, 41, 53, 25},
68 {0, 64, 8, 42, 44, 52, 27},
69 {44, 64, 5, 42, 44, 52, 33},
70 {749, 64, 8, 42, 48, 51, 31},
71 {586, 64, 8, 42, 60, 51, 44},
72 {843, 64, 8, 42, 46, 51, 30},
73 {889, 64, 9, 42, 46, 51, 28},
74 {260, 116, 7, 42, 42, 51, 27},
75 {202, 0, 4, 46, 29, 64, 16},
76 {39, 0, 10, 46, 39, 64, 18},
77 {231, 0, 9, 46, 29, 64, 16},
78 {329, 167, 7, 42, 41, 36, 27},
79 {583, 167, 9, 4, 42, 22, 23},
80 {490, 167, 6, 46, 27, 28, 18},
81 {695, 116, 7, 34, 38, 44, 25},
82 {458, 0, 5, 46, 40, 56, 28},
83 {733, 116, 7, 34, 37, 44, 22},
84 {498, 0, 7, 46, 40, 56, 28},
85 {655, 116, 7, 34, 40, 44, 27},
86 {641, 0, 5, 46, 33, 55, 18},
87 {250, 64, 7, 34, 40, 52, 27},
88 {603, 0, 5, 46, 38, 55, 27},
89 {894, 0, 6, 44, 24, 53, 12},
90 {282, 0, 12, 44, 30, 62, 12},
91 {564, 0, 5, 46, 39, 55, 25},
92 {538, 0, 5, 46, 26, 56, 13},
93 {860, 116, 5, 34, 52, 43, 41},
94 {0, 167, 5, 34, 38, 43, 27},
95 {613, 116, 7, 34, 42, 44, 28},
96 {290, 64, 5, 34, 40, 52, 28},
97 {330, 64, 7, 34, 40, 52, 28},
98 {113, 167, 5, 34, 33, 43, 18},
99 {770, 116, 7, 34, 36, 44, 21},
100 {499, 116, 5, 42, 33, 51, 19},
101 {38, 167, 5, 34, 38, 43, 27},
102 {912, 116, 8, 34, 41, 43, 24},
103 {806, 116, 8, 34, 54, 43, 37},
104 {953, 116, 8, 34, 41, 43, 24},
105 {129, 64, 9, 34, 41, 52, 24},
106 {76, 167, 7, 34, 37, 43, 22},
107 {78, 0, 7, 46, 32, 64, 16},
108 {260, 0, 4, 46, 22, 64, 13},
109 {110, 0, 9, 46, 32, 64, 16},
110 {517, 167, 7, 27, 41, 26, 27},
111 };
112
113 static struct sdf_font font_Ubuntu = {"Ubuntu", 48, 1024, 256, characters_Ubuntu};
114
115 vg_tex2d tex_ubuntu = { .path = "textures/ubuntu.qoi" };
116
117 // TEXTURES
118 // ===========================================================================================================
119
120 vg_tex2d tex_tile_data = { .path = "textures/tileset.qoi" };
121 vg_tex2d tex_tile_detail = { .path = "textures/tile_overlays.qoi" };
122 vg_tex2d tex_wood = { .path = "textures/wood.qoi" };
123 vg_tex2d tex_ball_noise = { .path = "textures/bnoise.qoi" };
124 vg_tex2d tex_monofur = { .path = "textures/ascii.qoi", .flags = VG_TEXTURE_NO_MIP };
125 vg_tex2d tex_unkown = { .path = "textures/unkown.qoi" };
126 vg_tex2d tex_buttons = { .path = "textures/buttons.qoi" };
127
128 vg_tex2d *texture_list[] = { &tex_tile_detail, &tex_tile_data, &tex_wood, &tex_ball_noise, &tex_monofur, &tex_unkown, &tex_buttons, &tex_ubuntu };
129
130 // AUDIO
131 // ===========================================================================================================
132
133 sfx_vol_control audio_volume_sfx = { .val = 1.0f, .name = "Sound effects" };
134 sfx_vol_control audio_volume_music = { .val = 1.0f, .name = "Music" };
135
136 sfx_system audio_system_sfx =
137 {
138 .vol = 1.f,
139 .ch = 1,
140 .vol_src = &audio_volume_sfx,
141 .name = "sfx"
142 };
143
144 sfx_set audio_tile_mod =
145 {
146 .sources = "\
147 sound/mod_01.ogg\0\
148 sound/mod_02.ogg\0\
149 sound/mod_03.ogg\0\
150 sound/mod_04.ogg\0\
151 sound/mod_05.ogg\0\
152 sound/mod_06.ogg\0",
153 .flags = 0
154 };
155
156 sfx_set audio_splitter =
157 {
158 .sources = "\
159 sound/splitter_01.ogg\0"
160 };
161
162 sfx_set audio_rolls =
163 {
164 .sources = "\
165 sound/rolling_01.ogg\0\
166 sound/rolling_02.ogg\0"
167 };
168
169 sfx_set audio_random =
170 {
171 .sources = "\
172 sound/random_01.ogg\0\
173 sound/random_02.ogg\0\
174 sound/random_03.ogg\0\
175 sound/random_04.ogg\0\
176 sound/random_05.ogg\0\
177 sound/random_06.ogg\0\
178 sound/random_07.ogg\0\
179 sound/random_08.ogg\0"
180 };
181
182 sfx_set audio_clicks =
183 {
184 .sources = "\
185 sound/click_a.ogg\0\
186 sound/click_b.ogg\0\
187 sound/click_c.ogg\0"
188 };
189
190 sfx_set audio_tones =
191 {
192 .sources = "\
193 sound/y0.ogg\0\
194 sound/y1.ogg\0\
195 sound/y2.ogg\0\
196 sound/y3.ogg\0\
197 sound/y4.ogg\0\
198 sound/y5.ogg\0\
199 sound/y6.ogg\0\
200 sound/y7.ogg\0\
201 sound/y8.ogg\0"
202 };
203
204 // One two or three layers of rolling noise
205 sfx_system audio_system_balls_rolling =
206 {
207 .vol = 0.7f, .ch = 1, .vol_src = &audio_volume_sfx,
208 .name = "Balls Rolling", .flags = SFX_FLAG_REPEAT | SFX_FLAG_PERSISTENT
209 };
210
211 // Various oneshots
212 sfx_system audio_system_balls_switching =
213 {
214 .vol = 0.2f, .ch = 1, .vol_src = &audio_volume_sfx,
215 .name = "Balls Switching"
216 };
217
218 // Gameplay critical sounds eg. splitter sound rocking
219 sfx_system audio_system_balls_important =
220 {
221 .vol = 1.f, .ch = 1, .vol_src = &audio_volume_sfx,
222 .name = "Balls Gameplay"
223 };
224
225 // Suplemental sounds
226 sfx_system audio_system_balls_extra =
227 {
228 .vol = 0.27f, .ch = 1, .vol_src = &audio_volume_sfx,
229 .name = "Balls Extra"
230 };
231
232 sfx_system audio_system_ui =
233 {
234 .vol = 1.f, .ch = 1, .vol_src = &audio_volume_sfx,
235 .name = "UI"
236 };
237
238 ui_colourset ui_fl_colours = {
239 .main = 0xff807373,
240 .hover = 0xff918484,
241 .active = 0xffad9f9e
242 };
243
244 ui_colourset ui_fl_colours_inactive = {
245 .main = 0xff655958,
246 .hover = 0xff655958,
247 .active = 0xff655958
248 };
249
250 static void resource_load_main(void)
251 {
252 // Textures // UI
253 vg_tex2d_init( texture_list, vg_list_size( texture_list ) );
254 ui_global_ctx.colours_main = &ui_fl_colours;
255 gui_reset_colours();
256
257 // Audio
258 sfx_set_init( &audio_tile_mod, NULL );
259 sfx_set_init( &audio_splitter, NULL );
260 sfx_set_init( &audio_rolls, NULL );
261 sfx_set_init( &audio_random, NULL );
262 sfx_set_init( &audio_clicks, NULL );
263 sfx_set_init( &audio_tones, NULL );
264 }
265
266 static void resource_free_main(void)
267 {
268 vg_tex2d_free( texture_list, vg_list_size( texture_list ) );
269
270 sfx_set_free( &audio_tile_mod );
271 sfx_set_free( &audio_splitter );
272 sfx_set_free( &audio_rolls );
273 sfx_set_free( &audio_random );
274 sfx_set_free( &audio_clicks );
275 sfx_set_free( &audio_tones );
276 }
277
278 // SHADERS
279 // ===========================================================================================================
280
281 SHADER_DEFINE( shader_tile_colour,
282
283 // VERTEX
284 "layout (location=0) in vec2 a_co;"
285 "uniform mat3 uPv;"
286 "uniform vec3 uOffset;"
287 ""
288 "void main()"
289 "{"
290 "gl_Position = vec4( uPv * vec3( a_co * uOffset.z + uOffset.xy, 1.0 ), 1.0 );"
291 "}",
292
293 // FRAGMENT
294 "out vec4 FragColor;"
295 "uniform vec4 uColour;"
296 ""
297 "void main()"
298 "{"
299 "FragColor = uColour;"
300 "}"
301 ,
302 UNIFORMS({ "uPv", "uOffset", "uColour" })
303 )
304
305 SHADER_DEFINE( shader_ball,
306 // VERTEX
307 "layout (location=0) in vec2 a_co;"
308 "uniform vec3 uOffset;"
309 "uniform mat3 uPv;"
310 ""
311 "out vec4 aTexCoords;"
312 ""
313 "void main()"
314 "{"
315 // Vertex transform
316 "vec3 worldpos = vec3( (a_co * 0.5 - 0.25) * uOffset.z + uOffset.xy, 1.0 );"
317 "gl_Position = vec4( uPv * worldpos, 1.0 );"
318
319 // Create texture coords
320 "aTexCoords = vec4( a_co, worldpos.xy );"
321 "}",
322
323 // FRAGMENT
324 "out vec4 FragColor;"
325 ""
326 "uniform sampler2D uTexMain;"
327 "uniform vec3 uColour;"
328 "uniform vec2 uTexOffset;"
329 ""
330 "in vec4 aTexCoords;"
331 ""
332 "void main()"
333 "{"
334 "vec2 center_coords = aTexCoords.xy - 0.5;"
335 "vec2 center_coords_sqr = center_coords*center_coords;"
336 "float circle_factor = smoothstep( 0.07, 0.0625, center_coords_sqr.x+center_coords_sqr.y );"
337
338 "float bulge_amt = center_coords_sqr.x+center_coords_sqr.y;"
339 "vec2 warped_coords = aTexCoords.zw+uTexOffset - center_coords;"
340 "vec4 noise_sample = texture( uTexMain, warped_coords );"
341
342 "float rim_light = (center_coords_sqr.x+center_coords_sqr.y)*15.0;"
343
344 "vec2 shadow_coords = center_coords + vec2(0.02,0.07);"
345 "vec2 shadow_coords_sqr = shadow_coords*shadow_coords;"
346 "float shadow = exp(-((shadow_coords_sqr.x+shadow_coords_sqr.y)-0.0125)*15.0);"
347
348 "vec3 marble_comp = uColour*0.9 + (noise_sample.x*0.7+pow(rim_light,3.0)*2.0) * 0.1;"
349 "vec4 colour_comp = mix( vec4(0.74,0.53,0.34,shadow), vec4(marble_comp,1.0), circle_factor );"
350
351 "FragColor = colour_comp;"
352 "}"
353 ,
354 UNIFORMS({ "uTexMain", "uColour", "uOffset", "uPv", "uTexOffset" })
355 )
356
357 SHADER_DEFINE( shader_tile_main,
358 // VERTEX
359 "layout (location=0) in vec2 a_co;"
360 "uniform vec4 uOffset;" // Tile x/y, uv x/y
361 "uniform mat3 uPv;"
362 "uniform mat2 uSubTransform;"
363 ""
364 "out vec4 aTexCoords;"
365 "out vec2 aWorldCoords;"
366 ""
367 "vec2 hash22(vec2 p)"
368 "{"
369 "vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));"
370 "p3 += dot(p3, p3.yzx+33.33);"
371 "return fract((p3.xx+p3.yz)*p3.zy);"
372 "}"
373 ""
374 "void main()"
375 "{"
376 // Vertex transform
377 "vec2 subtransform = uSubTransform * (a_co-0.5) + 0.5;"
378 "vec3 worldpos = vec3( subtransform + uOffset.xy, 1.0 );"
379 "gl_Position = vec4( uPv * worldpos, 1.0 );"
380
381 // Create texture coords
382 "vec2 random_offset = floor(hash22(uOffset.xy) * 4.0) * 0.25;"
383 "vec2 edge_safe_coords = a_co * 0.98 + 0.01;"
384 "aTexCoords = vec4((edge_safe_coords + uOffset.zw) * 0.25, edge_safe_coords * 0.25 + random_offset );"
385 "aWorldCoords = worldpos.xy;"
386 "}",
387
388 // FRAGMENT
389 "out vec4 FragColor;"
390 ""
391 "uniform sampler2D uTexGlyphs;"
392 "uniform sampler2D uTexWood;"
393 "uniform float uGhost;"
394 "uniform float uForeground;"
395 "uniform vec2 uMousePos;"
396 "uniform vec4 uColour;"
397 ""
398 "in vec4 aTexCoords;"
399 "in vec2 aWorldCoords;"
400 ""
401 "void main()"
402 "{"
403 "vec3 shadowing_colour = vec3( 0.93, 0.88536, 0.8184 ) * 0.97;"
404 "vec4 glyph = texture( uTexGlyphs, aTexCoords.xy );"
405 "vec4 wood = texture( uTexWood, aTexCoords.zw );"
406 "vec4 wood_secondary = texture( uTexWood, aTexCoords.zw + 0.25 );"
407 "vec3 wood_comp = mix( wood_secondary.rgb * shadowing_colour, wood.rgb, clamp( glyph.b * 2.0 - 1.0, 0.0, 1.0 ) );"
408
409 "vec3 shadows = mix( vec3( 0.85, 0.7344, 0.561 ), vec3(1.0,1.0,1.0), glyph.r );"
410
411 "vec4 output_regular = vec4( wood_comp * shadows, mix( glyph.a, glyph.b, uForeground ) );"
412
413 "float ghost_dist = clamp( 1.5 - distance(uMousePos, aWorldCoords), 0.0, 1.0 );"
414 "vec4 output_ghost = vec4( 1.0, 1.0, 1.0, glyph.g * ghost_dist );"
415
416 "FragColor = mix( output_regular, output_ghost, uGhost ) * uColour;"
417 "}"
418 ,
419 UNIFORMS({ "uPv", "uOffset", "uTexGlyphs", "uTexWood", "uSubTransform", "uGhost", "uMousePos", "uColour", "uForeground" })
420 )
421
422 SHADER_DEFINE( shader_background,
423 // VERTEX
424 "layout (location=0) in vec2 a_co;"
425 "uniform mat3 uPv;"
426 "uniform vec3 uOffset;"
427 ""
428 "out vec2 aTexCoords;"
429 ""
430 "void main()"
431 "{"
432 "vec2 world_pos = a_co * uOffset.z + uOffset.xy;"
433 "gl_Position = vec4( uPv * vec3( world_pos, 1.0 ), 1.0 );"
434 "aTexCoords = a_co;"
435 "}",
436
437 // FRAGMENT
438 "out vec4 FragColor;"
439 ""
440 "uniform sampler2D uTexMain;"
441 "uniform sampler2D uSamplerNoise;"
442 "uniform float uVariance;"
443 ""
444 "in vec2 aTexCoords;"
445 ""
446 "void main()"
447 "{"
448 "float ao_accum = 0.0;"
449 "for( int i=0; i<10; ++i )"
450 "{"
451 "vec2 random_noise = (texture( uSamplerNoise, aTexCoords * 20.0 + float(i) * 0.2 ).xy - vec2( 0.5, 0.5 )) * uVariance;"
452 "vec4 background = texture( uTexMain, aTexCoords + random_noise );"
453 "ao_accum += background.r * clamp((1.0 - length( random_noise )), 0.0, 1.0);"
454 "}"
455 "ao_accum *= 0.15;"
456
457 "vec4 data_this_tile = texture( uTexMain, aTexCoords );"
458
459 "ao_accum -= data_this_tile.r;"
460
461 "vec3 colour_main = mix( vec3( 0.369768, 0.3654, 0.42 ),vec3( 0.275, 0.388, 0.553 ), data_this_tile.g );"
462
463 "vec2 square_coords = fract( aTexCoords * 64.0 );"
464 "vec2 grid_coords = abs( square_coords - 0.5 );"
465 "float edge_contrast = (1.0-ao_accum*0.2);"
466
467 "float gridline = step( 0.49, max(grid_coords.x,grid_coords.y) );"
468 "float gridline_fadeout = min(max(edge_contrast-1.0, 0.0)*40.0 + data_this_tile.g,10.0);"
469
470 "FragColor = vec4( colour_main * edge_contrast + gridline * 0.02 * gridline_fadeout, 1.0 );"
471 "}"
472 ,
473 UNIFORMS({ "uPv", "uOffset", "uTexMain", "uVariance", "uSamplerNoise" })
474 )
475
476 SHADER_DEFINE( shader_wire,
477 // VERTEX
478 "layout (location=0) in vec2 a_co;"
479 "uniform vec3 uStart;"
480 "uniform vec3 uEnd;"
481 "uniform mat3 uPv;"
482 "uniform float uCurve;"
483 ""
484 "out vec2 aTexCoords;"
485 ""
486 "vec3 sample_curve_time( float t )"
487 "{"
488 "vec3 line_coord = mix( uStart, uEnd, t );"
489
490 "float curve_amt = 1.0-(pow((t*2.0-1.0),2.0));"
491 "return vec3( line_coord.x, line_coord.y - curve_amt*uCurve, line_coord.z );"
492 "}"
493 ""
494 "void main()"
495 "{"
496 // Vertex transform
497 "vec3 p0 = sample_curve_time( a_co.x );"
498 "vec3 p1 = sample_curve_time( a_co.x + 0.025 );"
499
500 "vec2 line_tangent = normalize(p1.xy-p0.xy);"
501 "vec2 line_normal = vec2( -line_tangent.y, line_tangent.x );"
502
503 "vec2 worldfinal = p0.xy + line_normal*a_co.y*p0.z;"
504
505 "gl_Position = vec4( uPv * vec3(worldfinal, 1.0), 1.0 );"
506
507 // Create texture coords (todo: include stretch adjusted coords?)
508 "aTexCoords = vec2( a_co.x, a_co.y + 0.5 );"
509 "}",
510
511 // FRAGMENT
512 "out vec4 FragColor;"
513 ""
514 "uniform sampler2D uTexMain;"
515 "uniform vec4 uColour;"
516 "uniform float uTime;"
517 "uniform float uGlow;"
518 ""
519 "in vec2 aTexCoords;"
520 ""
521 "void main()"
522 "{"
523 // Compute shadowing
524 "float shadow = 1.0 - abs(aTexCoords.y - 0.5) * 2.0;"
525 "float masking = smoothstep( 0.5, 0.8, shadow );"
526
527 "vec3 colour_comp = mix( vec3(0.0,0.0,0.0), uColour.rgb, masking );"
528
529 "float flow_thing = fract( aTexCoords.x + uTime );"
530 "vec3 final_comp = colour_comp + flow_thing * uGlow;"
531
532 "FragColor = vec4( final_comp, max( shadow* 0.2, masking ) * uColour.a );"
533 "}"
534 ,
535 UNIFORMS({ "uPv", "uColour", "uTexMain", "uStart", "uEnd", "uCurve", "uTime", "uGlow" })
536 )
537
538 SHADER_DEFINE( shader_buttons,
539 // VERTEX
540 "layout (location=0) in vec2 a_co;"
541 "uniform vec4 uOffset;" // Tile x/y, uv x/y
542 "uniform mat3 uPv;"
543 ""
544 "out vec2 aTexCoords;"
545 ""
546 "void main()"
547 "{"
548 // Vertex transform
549 "vec3 worldpos = vec3( a_co + uOffset.xy, 1.0 );"
550 "gl_Position = vec4( uPv * worldpos, 1.0 );"
551
552 // Create texture coords
553 "vec2 edge_safe_coords = a_co * 0.98 + 0.01;"
554 "aTexCoords = (edge_safe_coords + uOffset.zw) * 0.25;"
555 "}",
556
557 // FRAGMENT
558 "out vec4 FragColor;"
559 ""
560 "uniform sampler2D uTexMain;"
561 "uniform vec4 uColour;" // rgb, light amount
562 ""
563 "in vec2 aTexCoords;"
564 ""
565 "void main()"
566 "{"
567 "vec4 glyph = texture( uTexMain, aTexCoords.xy );"
568
569 "FragColor = vec4( uColour.rgb * (mix(glyph.r, glyph.g, uColour.a)+0.02)*2.6 + glyph.b * 0.4, glyph.a );"
570 "}"
571 ,
572 UNIFORMS({ "uPv", "uOffset", "uTexMain", "uColour" })
573 )
574
575
576 void vg_register(void)
577 {
578 SHADER_INIT( shader_tile_colour );
579 SHADER_INIT( shader_tile_main );
580 SHADER_INIT( shader_ball );
581 SHADER_INIT( shader_background );
582 SHADER_INIT( shader_wire );
583 SHADER_INIT( shader_buttons );
584 }
585
586 /*
587 0000 0 | 0001 1 | 0010 2 | 0011 3
588 | | | | |
589 X | X= | X | X=
590 | | |
591 0100 4 | 0101 5 | 0110 6 | 0111 7
592 | | | | |
593 =X | =X= | =X | =X=
594 | | |
595 1000 8 | 1001 9 | 1010 10 | 1011 11
596 | | | | |
597 X | X= | X | X=
598 | | | | | | |
599 1100 12 | 1101 13 | 1110 14 | 1111 15
600 | | | | |
601 =X | =X= | =X | =X=
602 | | | | | | |
603 */
604
605 struct cmp_level
606 {
607 const char *map_name;
608 const char *title;
609 const char *description;
610
611 int unlocked;
612 int completed_score;
613
614 int _unlock, _linked; // When completed, unlock this level
615 struct cmp_level *unlock, *linked;
616
617 int serial_id;
618 int is_tutorial;
619
620 SteamLeaderboard_t steam_leaderboard;
621 };
622
623 static struct cmp_level cmp_levels_tutorials[] =
624 {
625 // r1
626 {
627 .serial_id = 0,
628 .title = "PRINCIPLE 1",
629 .map_name = "cmp_t01",
630 .description =
631 "Utilize basic transport methods",
632
633 ._unlock = 1,
634 .is_tutorial = 1
635 },
636 // r1
637 {
638 .serial_id = 1,
639 .title = "PRINCIPLE 2",
640 .map_name = "cmp_t02",
641 .description =
642 "Utilize the twisty turny(TM) piece to split the marble\n"
643 "stream into two",
644
645 ._unlock = 2,
646 .is_tutorial = 1,
647 },
648 // r1
649 {
650 .serial_id = 2,
651 .title = "PRINCIPLE 3",
652 .map_name = "cmp_t03",
653 .description =
654 "Merge transport into one path",
655
656 ._unlock = 12,
657 .is_tutorial = 1
658 },
659 // r1
660 {
661 .serial_id = 12,
662 .title = "PRINCIPLE 4",
663 .map_name = "cmp_t04",
664 .description =
665 "Some stages require multiple runs to succeed in order to\n"
666 "pass",
667
668 ._unlock = 6,
669 .is_tutorial = 1
670 }
671 };
672
673 static struct cmp_level cmp_levels_basic[] =
674 {
675 // r2 GM
676 {
677 .serial_id = 6,
678 .title = "PATCH",
679 .map_name = "cmp_b04",
680 .description =
681 "For some reason, the division module our intern built\n"
682 "for us is sending twice as many yellows as needed. Send\n"
683 "the excess to be recycled!",
684
685 ._unlock = 7,
686 ._linked = 3
687 },
688 // r1 GM
689 {
690 .serial_id = 3,
691 .title = "SUBDIVISION 1",
692 .map_name = "cmp_b01",
693 .description =
694 "Sometimes getting the desired amount takes dividing up\n"
695 "the input and recombining it.",
696
697 ._linked = 4,
698 ._unlock = 5
699 },
700 // r1 GM
701 {
702 .serial_id = 4,
703 .title = "SUBDIVISION 2",
704 .map_name = "cmp_b02",
705 .description =
706 "",
707
708 ._unlock = 7
709 },
710 // r1 GM
711 {
712 .serial_id = 5,
713 .title = "RESTRUCTURE",
714 .map_name = "cmp_b03",
715 .description =
716 "It is possible to swap these values using simple\n"
717 "division and addition.",
718
719 ._unlock = 8
720 },
721 // r2 GM
722 {
723 .serial_id = 7,
724 .title = "PATTERNS 1",
725 .map_name = "cmp_b05",
726 .description =
727 "Replicate the pattern",
728
729 ._linked = 8
730 },
731 // r2 GM
732 {
733 .serial_id = 8,
734 .title = "PATTERNS 2",
735 .map_name = "cmp_b06",
736 .description =
737 "Replicate MORE",
738
739 ._unlock = 15
740 },
741 // r2 GM
742 {
743 .serial_id = 15,
744 .title = "PRINCIPLE 5",
745 .map_name = "cmp_b10",
746 .description =
747 "The sharp engineers among you may have already spotted\n"
748 "and utilized this part of the system\n"
749 "\n"
750 "We forgot to include the relevant principle tasks as\n"
751 "of your training package, you will now be tasked to\n"
752 "complete them",
753
754 ._unlock = 16,
755 .is_tutorial = 1
756 },
757 // r2 GM
758 {
759 .serial_id = 16,
760 .title = "ROUTING PROBLEM",
761 .map_name = "cmp_routing",
762 .description =
763 "Things can get a little chaotic on tight boards, do your\n"
764 "best to utilize principle 5 to get the job done\n",
765
766 ._linked = 9
767 },
768 // r2 GM
769 {
770 .serial_id = 9,
771 .title = "MIGHTY CONSUMER",
772 .map_name = "cmp_b07",
773 .description =
774 "Build a greedy system",
775
776 ._linked = 10,
777 ._unlock = 11
778 },
779 {
780 .serial_id = 10,
781 .title = "SHIFT",
782 .map_name = "cmp_b08",
783 .description =
784 "",
785
786 ._unlock = 17
787 },
788 // r2 GM
789 {
790 .serial_id = 11,
791 .title = "REVERSE",
792 .map_name = "cmp_b09",
793 .description =
794 "Reverse the incoming order. Always length 4",
795
796 ._unlock = 17
797 },
798 // r2 GM
799 {
800 .serial_id = 17,
801 .title = "PRINCIPLE 6",
802 .map_name = "cmp_b11",
803 .description =
804 "Usually the splitter piece will flip flop between left\n"
805 "and right, however it can be forced to only rotate in\n"
806 "one direction if trigger wires are attached.\n"
807 "\n"
808 "Right click and drag from a regular block, and attach it\n"
809 "to a splitter. This creates a trigger.\n"
810 "The default state is left, and once a marble hits the\n"
811 "trigger it will switch to rotating that direction.",
812
813 ._unlock = 18,
814 .is_tutorial = 1
815 },
816 // r2 GM
817 {
818 .serial_id = 18,
819 .title = "NOT GATE",
820 .map_name = "cmp_not",
821 .description =
822 "Test your knowledge of triggers, build an 'NOT GATE'\n"
823 "emulated by marble logic.",
824
825 ._linked = 19,
826 ._unlock = 20
827 },
828 // r2 GM
829 {
830 .serial_id = 19,
831 .title = "AND GATE",
832 .map_name = "cmp_and",
833 .description =
834 "A slightly more complicated gate, but shouldn't be\n"
835 "too difficult for your skillset.",
836
837 ._unlock = 20
838 },
839 // r2 GM
840 {
841 .serial_id = 20,
842 .title = "QUALIFICATION PROJECT",
843 .map_name = "cmp_xor",
844 .description =
845 "Significantly more complicated than an AND or NOT gate,\n"
846 "but possible.",
847
848 ._unlock = 13
849 }
850 };
851
852 static struct cmp_level cmp_levels_grad[] =
853 {
854 // r2
855 {
856 .serial_id = 13,
857 .title = "SORT",
858 .map_name = "cmp_i01",
859 .description =
860 "Devise a scheme to filter and sort the inputs. If you\n"
861 "believe you lack the tools required to solve this one,\n"
862 "take a harder look at the inputs.",
863 ._linked = 14
864
865 },
866 // r2
867 {
868 .serial_id = 14,
869 .title = "THIRDS",
870 .map_name = "cmp_i02",
871 .description =
872 "Split the inputs up into a third of their values\n"
873 "\n"
874 "Is this possible? -HG",
875 ._linked = 21
876
877 },
878 // r2 GM
879 {
880 .serial_id = 21,
881 .title = "SIMPLE ADDITION",
882 .map_name = "cmp_grad",
883 .description =
884 "Take the amount of yellows coming in, and add them\n"
885 "together. Send your result using the stream of blues.",
886
887 ._linked = 22
888 },
889 // r2 GM
890 {
891 .serial_id = 22,
892 .title = "SECRET CODE",
893 .map_name = "cmp_secret",
894 .description =
895 ""
896 }
897 };
898
899 #define NUM_CAMPAIGN_LEVELS (vg_list_size( cmp_levels_tutorials ) + vg_list_size( cmp_levels_basic ) + vg_list_size( cmp_levels_grad ))
900
901 static struct serializable_set
902 {
903 struct cmp_level *pack;
904 int count;
905 }
906 career_serializable[] =
907 {
908 {
909 .pack = cmp_levels_tutorials,
910 .count = vg_list_size( cmp_levels_tutorials )
911 },
912 {
913 .pack = cmp_levels_basic,
914 .count = vg_list_size( cmp_levels_basic )
915 },
916 {
917 .pack = cmp_levels_grad,
918 .count = vg_list_size( cmp_levels_grad )
919 }
920 };
921
922 // Setup pointers and that
923 static void career_local_data_init(void)
924 {
925 struct cmp_level *level_ptrs[ NUM_CAMPAIGN_LEVELS ];
926
927 // COllect pointers
928 for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
929 {
930 struct serializable_set *set = &career_serializable[i];
931
932 for( int j = 0; j < set->count; j ++ )
933 level_ptrs[ set->pack[j].serial_id ] = &set->pack[j];
934 }
935
936 // Apply
937 for( int i = 0; i < vg_list_size( career_serializable ); i ++ )
938 {
939 struct serializable_set *set = &career_serializable[i];
940
941 for( int j = 0; j < set->count; j ++ )
942 {
943 struct cmp_level *lvl = &set->pack[j];
944 lvl->unlock = lvl->_unlock? level_ptrs[ lvl->_unlock ]: NULL;
945 lvl->linked = lvl->_linked? level_ptrs[ lvl->_linked ]: NULL;
946 }
947 }
948 }