generated from 32blit/32blit-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 3
/
SuperSquareBros.cpp
6204 lines (5068 loc) · 204 KB
/
SuperSquareBros.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "SuperSquareBros.hpp"
using namespace blit;
// Note: if want to go hires, with lores graphics:
// screen.sprite(uint16_t sprite, const Point &position, const Point &origin, float scale, uint8_t transform)
// origin can be Point(0,0) and transform can be SpriteTransform::NONE, scale is 2
// e.g. screen.sprite(id, Point(x, y), Point(0, 0), 2.0f, SpriteTransform::NONE
#define RESET_SAVE_DATA_IF_MINOR_DIFF
//#define RESET_SAVE_DATA_ALWAYS
//#define TESTING_MODE
void init_game();
#ifdef PICO_BUILD
const uint16_t SCREEN_WIDTH = 120;
const uint16_t SCREEN_HEIGHT = 120;
#else
const uint16_t SCREEN_WIDTH = 160;
const uint16_t SCREEN_HEIGHT = 120;
#endif // PICO_BUILD
#ifdef PICO_BUILD
const uint8_t LEVEL_COUNT = 11;
#else
const uint8_t LEVEL_COUNT = 10;
#endif // PICO_BUILD
const uint8_t LEVEL_SELECT_NUMBER = LEVEL_COUNT + 2;
const uint8_t LEVELS_PER_WORLD = 4;
const uint8_t SNOW_WORLD = 1;
const uint8_t FADE_STEP = 3;
const float FRAME_LENGTH = 0.15f;
const float TRANSITION_FRAME_LENGTH = 0.1f;
const float TRANSITION_CLOSE_LENGTH = 0.5f;
const uint16_t TILE_ID_EMPTY = 255;
const uint16_t TILE_ID_COIN = 384;
const uint16_t TILE_ID_PLAYER_1 = 192;
const uint16_t TILE_ID_PLAYER_2 = 196;
const uint16_t TILE_ID_HEART = 416;
const uint16_t TILE_ID_CAMERA = 509;
const uint16_t TILE_ID_TRANSITION = 496;
const uint16_t TILE_ID_FINISH = 432;
const uint16_t TILE_ID_CHECKPOINT = 404;
const uint16_t TILE_ID_LEVEL_TRIGGER = 420;
const uint16_t TILE_ID_LEVEL_BRIDGE_MIN = 144;
const uint16_t TILE_ID_ENEMY_1 = 208;
const uint16_t TILE_ID_ENEMY_2 = 212;
const uint16_t TILE_ID_ENEMY_3 = 216;
const uint16_t TILE_ID_ENEMY_4 = 220;
const uint16_t TILE_ID_ENEMY_5 = 224;
const uint16_t TILE_ID_ENEMY_6 = 228;
const uint16_t TILE_ID_ENEMY_7 = 232;
const uint16_t TILE_ID_ENEMY_8 = 236;
const uint16_t TILE_ID_ENEMY_9 = 240;
const uint16_t TILE_ID_BOSS_1 = 256;
const uint16_t TILE_ID_BOSS_2 = 264;
const uint16_t TILE_ID_BIG_BOSS = 288;
const uint16_t TILE_ID_SPIKE_BOTTOM = 480;
const uint16_t TILE_ID_SPIKE_TOP = 481;
const uint16_t TILE_ID_SPIKE_LEFT = 482;
const uint16_t TILE_ID_SPIKE_RIGHT = 483;
const uint16_t TILE_ID_ENEMY_PROJECTILE_ROCK = 472;
const uint16_t TILE_ID_ENEMY_PROJECTILE_SNOWBALL = 473;
const uint16_t TILE_ID_ENEMY_PROJECTILE_BULLET = 474;
const uint16_t TILE_ID_BOSS_PROJECTILE_ROCK = 476;
const uint16_t TILE_ID_BOSS_PROJECTILE_SNOWBALL = 477;
const uint16_t TILE_ID_HUD_LIVES = 422;
const uint16_t TILE_ID_HUD_COINS = 424;
const uint16_t TILE_ID_HUD_ENEMIES_KILLED = 425;
const uint16_t TILE_ID_HUD_TIME_TAKEN = 426;
const uint16_t TILE_ID_GOLD_BADGE = 428;
const float CAMERA_SCALE_X = 10.0f;
const float CAMERA_SCALE_Y = 5.0f;
const float CAMERA_PAN_TIME = 7.0f;
const float CAMERA_PAN_TIME_FINAL_LEVEL = 2.0f;
const float CAMERA_NEW_WORLD_TIME = 3.0f;
const float NEW_WORLD_DELAY_TIME = 2.0f;
const float CAMERA_RESPAWN_LOCK_MIN = 1.0f;
const float LEVEL_DEATH_BOUNDARY_SCALE = 1.5f;
const uint8_t SPRITE_SIZE = 8;
const uint16_t SG_ICON_INDEX = 128;
const uint8_t SG_ICON_SIZE = SPRITE_SIZE * 4;
const float SNOW_LEVEL_GENERATE_DELAY = 0.1f;
const float SNOW_LEVEL_SELECT_GENERATE_DELAY = 0.15f;
const uint16_t SNOW_LEVEL_INIT_COUNT = 300;
const uint16_t SNOW_LEVEL_SELECT_INIT_COUNT = 200;
const float SCREEN_SHAKE_SHAKINESS = 3.0f; //pixels either way - maybe more?
const float REPEL_PLAYER_MIN = 5.0f;
const uint8_t ENTITY_DEATH_PARTICLE_COUNT = 100;
const float ENTITY_DEATH_PARTICLE_GRAVITY_X = 0.0f;
const float ENTITY_DEATH_PARTICLE_GRAVITY_Y = 60.0f;
const float ENTITY_DEATH_PARTICLE_AGE = 1.0f;
const float ENTITY_DEATH_PARTICLE_SPEED = 60.0f;
const uint8_t BOSS_DEATH_PARTICLE_COUNT = 200;
const float BOSS_DEATH_PARTICLE_GRAVITY_X = 0.0f;
const float BOSS_DEATH_PARTICLE_GRAVITY_Y = 60.0f;
const float BOSS_DEATH_PARTICLE_AGE = 1.4f;
const float BOSS_DEATH_PARTICLE_SPEED = 70.0f;
const float PLAYER_SLOW_PARTICLE_GRAVITY_X = 0.0f;
const float PLAYER_SLOW_PARTICLE_GRAVITY_Y = -30.0f;
const float PLAYER_SLOW_PARTICLE_AGE = 0.8f;
const float PLAYER_SLOW_PARTICLE_SPEED = 50.0f;
const uint8_t PLAYER_SLOW_PARTICLE_WIGGLE = 1;
const float PLAYER_SLOW_PARTICLE_SPAWN_DELAY = 0.05f;
const uint8_t CHECKPOINT_PARTICLE_COUNT = 250;
const float CHECKPOINT_PARTICLE_SPEED = 70.0f;
const float FINISH_PARTICLE_SPAWN_DELAY = 0.05f;
const float GRAVITY = 600.0f;
const float GRAVITY_MAX = 190.0f;
const float PROJECTILE_GRAVITY = 55.0f;
const float PROJECTILE_GRAVITY_MAX = 100.0f;
const uint8_t PLAYER_START_LIVES = 3;
const uint8_t PLAYER_MAX_HEALTH = 3;
const float PLAYER_MAX_JUMP = 190.0f;
//const float PLAYER_ATTACK_JUMP = 90.0f;
const float PLAYER_ATTACK_JUMP_SCALE = 0.65f;
const float PLAYER_ATTACK_JUMP_MIN = 90.0f;
const float PLAYER_MAX_SPEED = 87.0f;
const float PLAYER_IMMUNE_TIME = 2.0f;
const float PLAYER_ACCELERATION = 370.0f;
const float PLAYER_DECELERATION = 330.0f;
const float PLAYER_JUMP_COOLDOWN = 0.4f;
const float PLAYER_JUMP_MIN_AIR_TIME = 0.05f;
//const float PLAYER_JUMP_EXTRA_GRAVITY = 500.0f;
const float PLAYER_JUMP_EXTRA_DOWNSCALE = 0.92f;
const float PLAYER_SLOW_MAX_JUMP = 110.0f;
const float PLAYER_SLOW_MAX_SPEED = 15.0f;
const float PLAYER_SLOW_ACCELERATION = 150.0f;
const float PLAYER_SLOW_DECELERATION = 100.0f;
const float PLAYER_SLOW_JUMP_COOLDOWN = 0.3f;
const float ENTITY_IDLE_SPEED = 40.0f;
const float ENTITY_PURSUIT_SPEED = 55.0f;
const float ENTITY_JUMP_SPEED = 160.0f;
const float ENTITY_JUMP_COOLDOWN = 0.5f;
const float BOSS_INJURED_TIME = 0.3f;
const float BOSS_IMMUNE_TIME = 1.0f;
const float BOSS_1_IDLE_SPEED = 30.0f;
const float BOSS_1_PURSUIT_SPEED = 50.0f;
const float BOSS_1_ANGRY_SPEED = 105.0f;
const float BOSS_1_SPEED_REDUCTION_SCALE = 0.7f;
const float BOSS_1_JUMP_SPEED = 160.0f;
const float BOSS_1_ANGRY_JUMP_SPEED = 220.0f;
const float BOSS_1_JUMP_COOLDOWN = 1.5f;
const float BOSS_1_MINION_SPAWN_COOLDOWN = 1.5f;
const float BOSS_1_MINION_SPEED = 25.0f;
const float BOSS_1_MINION_SPEED_REDUCTION = 4.0f;
const float BOSS_1_JUMP_TRIGGER_MAX_RANGE = SPRITE_SIZE * 8;
const float BOSS_1_IGNORE_MIN_RANGE = SPRITE_SIZE * 9;
const float BOSS_1_INJURED_MAX_RANGE = SPRITE_SIZE * 12; //todo: is this right? reduce for pico - so doesn't go off screen
const float BOSS_1_DEATH_MAX_RANGE = SPRITE_SIZE * 16;
const float BOSS_1_RETURN_TO_SPAWN_RANGE = SPRITE_SIZE * 4;
const float BOSS_1_JUMP_SHAKE_TIME = 0.3f;
const float BOSS_1_ANGRY_JUMP_SHAKE_TIME = 0.35f;
const float BOSS_2_JUMP_SPEED = 160.0f;
const float BOSS_2_ANGRY_JUMP_SPEED = 220.0f;
const float BOSS_2_JUMP_COOLDOWN = 1.5f;
const float BOSS_2_RELOAD_TIME = 2.0f;
const float BOSS_2_RAPID_RELOAD_TIME = 0.4f;
const float BOSS_2_SUPER_RAPID_RELOAD_TIME = 0.1f;
const uint8_t BOSS_2_RAPID_SHOT_COUNT = 3;
const float BOSS_2_PROJECTILE_FLIGHT_TIME = 1.1f;
const float BOSS_2_RAPID_PROJECTILE_FLIGHT_TIME = 0.8f;
const float BOSS_2_SUPER_RAPID_PROJECTILE_FLIGHT_TIME = 0.8f;
const float BOSS_2_RESET_COOLDOWN = 2.0f;
const float BOSS_2_INJURED_TIME = 0.3f;
const float BOSS_2_IMMUNE_TIME = 1.0f;
const float BOSS_2_JUMP_TRIGGER_MAX_RANGE = SPRITE_SIZE * 10;
const float BOSS_2_IGNORE_MIN_RANGE = SPRITE_SIZE * 11;
const float BOSS_2_JUMP_SHAKE_TIME = 0.3f;
const float BOSS_2_ANGRY_JUMP_SHAKE_TIME = 0.35f;
const float BIG_BOSS_IDLE_SPEED = 30.0f;
const float BIG_BOSS_PURSUIT_SPEED = 50.0f;
const float BIG_BOSS_RETREAT_SPEED = 20.0f;
//const float BIG_BOSS_ANGRY_SPEED = 100.0f;
const float BIG_BOSS_JUMP_SPEED = 180.0f;
const float BIG_BOSS_ANGRY_JUMP_SPEED = 240.0f;
const float BIG_BOSS_JUMP_COOLDOWN = 2.0f;
const float BIG_BOSS_MINION_SPAWN_COOLDOWN = 1.5f;
const float BIG_BOSS_JUMP_TRIGGER_MAX_RANGE = SPRITE_SIZE * 10;
const float BIG_BOSS_IGNORE_MIN_RANGE = SPRITE_SIZE * 12;
const float BIG_BOSS_INJURED_MAX_RANGE = SPRITE_SIZE * 10;
//const float BOSS_1_DEATH_MAX_RANGE = SPRITE_SIZE * 16;
const float BIG_BOSS_RETURN_TO_SPAWN_RANGE = SPRITE_SIZE * 4;
const float BIG_BOSS_JUMP_SHAKE_TIME = 0.45f;
const float BIG_BOSS_ANGRY_JUMP_SHAKE_TIME = 0.5f;
const float BIG_BOSS_RELOAD_TIME = 2.3f;
const float BIG_BOSS_RAPID_RELOAD_TIME = 0.4f;
const float BIG_BOSS_PROJECTILE_FLIGHT_TIME = 1.0f;
const float RANGED_MAX_RANGE = 64.0f;
const float RANGED_RELOAD_TIME = 2.0f;
const float RANGED_PROJECTILE_X_VEL_SCALE = 0.8f;
const float RANGED_PROJECTILE_Y_VEL_SCALE = 0.5f;
const float SHOOTING_MAX_RANGE_X = 64.0f;
const float SHOOTING_MAX_RANGE_Y = 32.0f;
const float SHOOTING_RELOAD_TIME = 2.5f;
const float SHOOTING_RAPID_RELOAD_TIME = 0.5f;
const uint8_t SHOOTING_ENEMY_CLIP_SIZE = 2;
const float BULLET_PROJECTILE_SPEED = 64.0f;
const float PURSUIT_MAX_RANGE = 48.0f;
const float LEVEL_INFO_MAX_RANGE = SPRITE_SIZE * 4;
const float TEXT_FLASH_TIME = 0.8f;
const float TEXT_JUMP_VELOCITY = 80.0f;
const float TEXT_GRAVITY = 280.0f;
const uint8_t NO_LEVEL_SELECTED = 255;
const uint8_t CHECKPOINT_FRAMES = 4;
const float CHECKPOINT_FRAME_LENGTH = 0.2f;
const uint16_t CONFETTI_INIT_COUNT = 400;
const float CONFETTI_GENERATE_DELAY = 0.05f;
const float THANKYOU_SPEED = 0.3f;
const uint8_t MESSAGE_STRINGS_COUNT = 7;
const uint8_t INPUT_TYPE_COUNT = 2;
const uint16_t BYTE_SIZE = 256;
const uint16_t DEFAULT_VOLUME = 0x5000;
#ifdef PICO_BUILD
const uint16_t TEXT_BORDER = SPRITE_SIZE;
#else
const uint16_t TEXT_BORDER = SPRITE_SIZE * 2;
#endif // PICO_BUILD
// NOTE: all positions (x,y) mark TOP LEFT corner of sprites
// NOTE: issue with rendering (tiles on left are a pixel out sometimes) is due to integers being added to floats. Something along lines of (int)floorf(camera.x) etc is recommended, but when I tried it I got strange results.
// If I implement that again, remember that all float calcs should be done, *then* casted, rather than casting each to int then adding etc
#ifdef PICO_BUILD
const uint8_t SETTINGS_COUNT = 3;
const std::string COINS_COLLECTED = "Coins:";
const std::string ENEMIES_KILLED = "Enemies:";
const std::string TIME_TAKEN = "Time:";
const std::string CONTROLLER_TEXT = "Pico";
#else
const uint8_t SETTINGS_COUNT = 2;
const std::string COINS_COLLECTED = "Coins collected:";
const std::string ENEMIES_KILLED = "Enemies killed:";
const std::string TIME_TAKEN = "Time taken:";
#ifdef TARGET_32BLIT_HW
const std::string CONTROLLER_TEXT = "32Blit";
#else
const std::string CONTROLLER_TEXT = "Controller";
#endif // TARGET_32BLIT_HW
#endif // PICO_BUILD
const uint16_t SCREEN_MID_WIDTH = SCREEN_WIDTH / 2;
const uint16_t SCREEN_MID_HEIGHT = SCREEN_HEIGHT / 2;
const uint8_t SPRITE_HALF = SPRITE_SIZE / 2;
const uint8_t SPRITE_QUARTER = SPRITE_SIZE / 4;
const uint16_t SCREEN_TILE_SIZE = (SCREEN_WIDTH / SPRITE_SIZE) * (SCREEN_HEIGHT / SPRITE_SIZE);
const uint8_t enemyHealths[] = { 1, 1, 1, 1, 2, 2, 2, 2, 1 };
const uint8_t bossHealths[] = { 3, 3, 3 };
const uint8_t bigBossMinions[] = { 7, 6, 4 };
const std::vector<uint16_t> coinFrames = { TILE_ID_COIN, TILE_ID_COIN + 1, TILE_ID_COIN + 2, TILE_ID_COIN + 3, TILE_ID_COIN + 2, TILE_ID_COIN + 1 };
const std::vector<uint16_t> finishFrames = { TILE_ID_FINISH, TILE_ID_FINISH + 1, TILE_ID_FINISH + 2, TILE_ID_FINISH + 3, TILE_ID_FINISH + 4, TILE_ID_FINISH + 5 };
const std::vector<uint16_t> transitionFramesClose = { TILE_ID_TRANSITION, TILE_ID_TRANSITION + 1, TILE_ID_TRANSITION + 2, TILE_ID_TRANSITION + 3, TILE_ID_TRANSITION + 4, TILE_ID_TRANSITION + 6, TILE_ID_TRANSITION + 7};
const std::vector<uint16_t> transitionFramesOpen = { TILE_ID_TRANSITION + 6, TILE_ID_TRANSITION + 5, TILE_ID_TRANSITION + 4, TILE_ID_TRANSITION + 3, TILE_ID_TRANSITION + 2, TILE_ID_TRANSITION + 1, TILE_ID_TRANSITION};
const float parallaxFactorLayersX[2] = {
0.4f,
0.2f
};
const float parallaxFactorLayersY[2] = {
0.4f,
0.2f
};
const uint8_t* asset_levels[] = {
asset_level0,
asset_level1,
asset_level2,
asset_level3,
asset_level4,
asset_level5,
asset_level6,
asset_level7,
asset_level8,
asset_level9,
#ifdef PICO_BUILD
asset_level10,
#endif // PICO_BUILD
asset_level_title,
asset_level_char_select,
asset_level_level_select
};
std::vector<uint16_t> snowParticleImages = {
464,
465
};
std::vector<uint16_t> confettiParticleImages = {
484,
485,
486,
487,
488,
489,
490,
491
};
const std::string messageStrings[MESSAGE_STRINGS_COUNT][INPUT_TYPE_COUNT] = {
{
"Press A to Start",
"Press U to Start"
},
{
"Press A to Skip",
"Press U to Skip"
},
{
"Press A",
"Press U"
},
{
"Press Y to Resume",
"Press P to Resume"
},
{
"Press A to Select",
"Press U to Select"
},
{
"Y - Back",
"P - Back"
},
{
"A - Toggle",
"U - Toggle"
}
};
const uint8_t levelTargets[LEVEL_COUNT][2][2] = {
{
// Level 1
{
// Score
25, // Gold
20 // Silver
},
{
// Enemies killed
4, // Gold
3 // Silver
}
},
{
// Level 2
{
// Score
22, // Gold
18 // Silver
},
{
// Enemies killed
5, // Gold
4 // Silver
}
},
{
// Level 3
{
// Score
22, // Gold
18 // Silver
},
{
// Enemies killed
7, // Gold
5 // Silver
}
},
{
// Level 4
{
// Score
10, // Gold
8 // Silver
},
{
// Enemies killed
14, // Gold
10 // Silver
}
},
{
// Level 5
{
// Score
23, // Gold
19 // Silver
},
{
// Enemies killed
9, // Gold
7 // Silver
}
},
{
// Level 6
{
// Score
25, // Gold
20 // Silver
},
{
// Enemies killed
10, // Gold
7 // Silver
}
},
{
// Level 7
{
// Score
21, // Gold
17 // Silver
},
{
// Enemies killed
8, // Gold
6 // Silver
}
},
{
// Level 8
{
// Score
20, // Gold
16 // Silver
},
{
// Enemies killed
10, // Gold
8 // Silver
}
},
#ifdef PICO_BUILD
{
// Level 9
{
// Score
24, // Gold
19 // Silver
},
{
// Enemies killed
10, // Gold
8 // Silver
}
},
{
// Level 10
{
// Score
22, // Gold
18 // Silver
},
{
// Enemies killed
16, // Gold
13 // Silver
}
},
#else
{
// Level 9
{
// Score
32, // Gold
26 // Silver
},
{
// Enemies killed
21, // Gold
16 // Silver
}
},
#endif // PICO_BUILD
{
// End Level
{
// Score
16, // Gold
13 // Silver
},
{
// Enemies killed
0, // Gold
0 // Silver
}
}
};
const float levelTargetTimes[LEVEL_COUNT][2] = {
// Level 1
{
// Time
12.5f, // Gold
14.0f // Silver
},
// Level 2
{
// Time
12.5f, // Gold
14.5f // Silver
},
// Level 3
{
// Time
12.5f, // Gold
14.5f // Silver
},
// Level 4
{
// Time
38.0f, // Gold
47.0f // Silver
},
// Level 5
{
// Time
13.0f, // Gold
15.5f // Silver
},
// Level 6
{
// Time
13.0f, // Gold
16.0f // Silver
},
// Level 7
{
// Time
13.0f, // Gold
16.5f // Silver
},
// Level 8
{
// Time
44.0f, // Gold
55.0f // Silver
},
#ifdef PICO_BUILD
// Level 9
{
// Time
20.0f, // Gold
24.0f // Silver
},
// Level 10
{
// Time
80.0f, // Gold TO CHECK + CHANGE IF NECESSARY
100.0f // Silver TO CHECK + CHANGE IF NECESSARY
},
#else
// Level 9
{
// Time
120.0f, // Gold
180.0f // Silver
},
#endif
// End level
{
// Time
4.2f, // Gold
4.5f // Silver
}
};
uint16_t levelDeathBoundary;
float dt;
uint32_t lastTime = 0;
//Surface* sg_icon_image = Surface::load(asset_scorpion_games);
//Surface* background_image = Surface::load(asset_background);
AudioHandler::AudioHandler audioHandler;
bool menuBack = false; // tells menu to go backwards instead of forwards.
bool gamePaused = false; // used for determining if game is paused or not.
bool coinSfxAlternator = false; // used for alternating channel used for coin pickup sfx
bool cameraIntro = false;
bool cameraRespawn = false;
bool cameraNewWorld = false;
uint16_t cameraStartX, cameraStartY;
uint16_t playerStartX, playerStartY;
//float windSpeed = 0;
float textFlashTimer = 0.0f;
uint8_t playerSelected = 0;
uint8_t pauseMenuItem = 0;
uint8_t menuItem = 0;
uint8_t settingsItem = 0;
uint8_t creditsItem = 0;
float snowGenTimer = 0.0f;
float confettiGenTimer = 0.0f;
bool slowPlayer = false;
bool dropPlayer = false;
bool repelPlayer = false;
bool bossBattle = false;
float thankyouValue = 0.0f;
#ifdef PICO_BUILD
const uint8_t MAX_HACKY_FAST_MODE = 2;
#endif // PICO_BUILD
uint8_t currentLevelNumber = NO_LEVEL_SELECTED;
uint8_t currentWorldNumber = 0;
// For version handling
struct GameVersion {
uint8_t major;
uint8_t minor;
uint8_t build;
} gameVersion;
// For metadata
GameMetadata metadata;
// struct to handle level data header...
// this will probably need to be revisited/reworked if 32blit-tools has *any* kind of update to it...
#pragma pack(push,1)
struct TMX16 {
char head[4];
uint16_t header_length;
uint16_t flags;
uint16_t empty_tile;
uint16_t width;
uint16_t height;
uint16_t layers;
uint16_t data[];
};
#pragma pack(pop)
enum class GameState {
STATE_SG_ICON,
STATE_INPUT_SELECT,
STATE_MENU,
STATE_CREDITS,
STATE_SETTINGS,
STATE_CHARACTER_SELECT,
STATE_LEVEL_SELECT,
STATE_IN_GAME,
STATE_LOST,
STATE_WON
};
GameState gameState = GameState::STATE_SG_ICON;
enum InputType {
CONTROLLER = 0,
KEYBOARD = 1
//NO_INPUT_TYPE
};
struct ButtonStates {
uint8_t UP;
uint8_t DOWN;
uint8_t LEFT;
uint8_t RIGHT;
uint8_t A;
uint8_t B;
uint8_t X;
uint8_t Y;
uint8_t JOYSTICK;
};
ButtonStates buttonStates = { 0 };
struct GameSaveData {
uint16_t version;
uint8_t inputType;
// Settings values
bool checkpoints = false;
bool musicVolume = true;
bool sfxVolume = true;
uint8_t hackyFastMode = 0;
} gameSaveData;
struct PlayerSaveData {
uint8_t levelReached;
};
PlayerSaveData allPlayerSaveData[2];
struct LevelSaveData {
uint8_t score;
uint8_t enemiesKilled;
float time;
};
LevelSaveData allLevelSaveData[2][LEVEL_COUNT];
// 0 slot is gameSaveData
// 1 slot is player 1 saveData
// 2..257 slots are player 1 levelData
// 258 slot is player 2 saveData
// 259..514 slots are player 2 levelData
/*int16_t get_version() {
return VERSION_MAJOR * 256 + VERSION_MINOR * 16 + VERSION_BUILD;
}*/
uint16_t get_version(GameVersion gameVersionData) {
return gameVersionData.major * 256 + gameVersionData.minor * 16 + gameVersionData.build;
}
GameVersion get_version_struct(uint16_t version) {
GameVersion gameVersionData{};
gameVersionData.major = version / 256;
version %= 256;
gameVersionData.minor = version / 16;
version %= 16;
gameVersionData.build = version;
return gameVersionData;
}
GameVersion parse_version(std::string versionString) {
GameVersion version{};
uint8_t startIndex, endIndex;
startIndex = 1;
endIndex = versionString.find('.');
version.major = (uint8_t)std::stoi(versionString.substr(startIndex, endIndex));
startIndex = endIndex + 1;
endIndex = versionString.find('.', startIndex);
version.minor = (uint8_t)std::stoi(versionString.substr(startIndex, endIndex));
startIndex = endIndex + 1;
endIndex = versionString.size();
version.build = (uint8_t)std::stoi(versionString.substr(startIndex, endIndex));
return version;
}
void save_game_data() {
// Write save data
write_save(gameSaveData);
}
void save_level_data(uint8_t playerID, uint8_t levelNumber) {
// Write level data
write_save(allLevelSaveData[playerID][levelNumber], (playerID * (BYTE_SIZE + 1)) + 1 + levelNumber + 1);
}
void save_player_data(uint8_t playerID) {
// Write level data
write_save(allPlayerSaveData[playerID], (playerID * (BYTE_SIZE + 1)) + 1);
}
LevelSaveData load_level_data(uint8_t playerID, uint8_t levelNumber) {
LevelSaveData levelSaveData;
if (read_save(levelSaveData, (playerID * (BYTE_SIZE + 1)) + 1 + levelNumber + 1)) {
// Success
}
else {
// Set some defaults
levelSaveData.score = 0;
levelSaveData.enemiesKilled = 0;
levelSaveData.time = 0.0f; // If time == 0.0f, game realises that it's a N/A time
}
return levelSaveData;
}
PlayerSaveData load_player_data(uint8_t playerID) {
PlayerSaveData playerSaveData;
if (read_save(playerSaveData, (playerID * (BYTE_SIZE + 1)) + 1)) {
// Success
}
else {
// Set some defaults
playerSaveData.levelReached = 0;
}
return playerSaveData;
}
void reset_save() {
gameSaveData.version = get_version(gameVersion);
gameSaveData.inputType = InputType::CONTROLLER;
gameSaveData.checkpoints = false;
gameSaveData.musicVolume = true;
gameSaveData.sfxVolume = true;
gameSaveData.hackyFastMode = 0;
save_game_data();
allPlayerSaveData[0].levelReached = 0;
save_player_data(0);
allPlayerSaveData[1].levelReached = 0;
save_player_data(1);
for (uint8_t i = 0; i < LEVEL_COUNT; i++) {
allLevelSaveData[0][i].score = 0;
allLevelSaveData[0][i].enemiesKilled = 0;
allLevelSaveData[0][i].time = 0.0f;
save_level_data(0, i);
allLevelSaveData[1][i].score = 0;
allLevelSaveData[1][i].enemiesKilled = 0;
allLevelSaveData[1][i].time = 0.0f;
save_level_data(1, i);
}
}
struct LevelData {
uint16_t levelWidth, levelHeight;
} levelData;
//struct PositionF {
// float x, y;
//};
//
//struct PositionI {
// int x, y;
//};
void render_sprite(uint16_t id, Point point) {
//screen.sprite(id, point, Point(0, 0), 1.0f, SpriteTransform::NONE);
screen.sprite(id, point);
}
void render_sprite(uint16_t id, Point point, SpriteTransform transform) {
//screen.sprite(id, point, Point(0, 0), 1.0f, transform);
screen.sprite(id, point, transform);
}
class ScreenShake {
public:
ScreenShake() {
set_shake(0);
set_shakiness(0);
}
ScreenShake(float shakiness) {
set_shake(0);
set_shakiness(shakiness);
}
void set_shake(float shake) {
this->shake = shake;
}
void set_shakiness(float shakiness) {
this->shakiness = 100 / shakiness;
}
float time_to_shake(float dt) {
if (shake > 0) {
shake -= dt;
if (shake < 0) {
shake = 0;
}
return (rand() % 201 - 100) / shakiness;
}
else {
return 0.0f;
}
}
protected:
float shake;
float shakiness;
};
ScreenShake shaker(SCREEN_SHAKE_SHAKINESS);
class Colour {
public:
uint8_t r, g, b, a;
Colour() {
r = g = b = a = 255;
}
Colour(uint8_t r, uint8_t g, uint8_t b) {
this->r = r;
this->g = g;
this->b = b;
a = 255;
}
Colour(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
};
// Particle colours
const std::vector<Colour> playerDeathParticleColours[2] = {
{ Colour(255, 255, 242), Colour(255, 204, 181), Colour(178, 53, 53) },
{ Colour(255, 255, 242), Colour(178, 214, 96), Colour(37, 124, 73) }
};
const std::vector<Colour> enemyDeathParticleColours[5] = {
{ Colour(255, 255, 242), Colour(184, 197, 216), Colour(25, 40, 102) },
{ Colour(255, 255, 242), Colour(255, 204, 181), Colour(165, 82, 139) },
{ Colour(255, 255, 242), Colour(255, 204, 181), Colour(229, 114, 57) },
{ Colour(255, 255, 242), Colour(204, 137, 124), Colour(127, 24, 75) },
{ Colour(255, 255, 242), Colour(145, 224, 204), Colour(53, 130, 130) }
};
const std::vector<Colour> bossDeathParticleColours[3] = {
{ Colour(255, 255, 242), Colour(184, 197, 216), Colour(25, 40, 102) },
{ Colour(255, 255, 242), Colour(255, 204, 181), Colour(165, 82, 139) },
{ Colour(255, 255, 242), Colour(184, 197, 216), Colour(25, 40, 102) }
};
const std::vector<Colour> levelTriggerParticleColours = { Colour(255, 255, 242), Colour(145, 224, 204), Colour(53, 130, 130) };
const std::vector<Colour> checkpointParticleColours[3] = {
{ Colour(255, 255, 242), Colour(184, 197, 216) },