From fefbbceef4a1a7839a8f1e8211a4a1cb9e5cc7fc Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Tue, 20 Aug 2024 20:56:28 -0500 Subject: [PATCH] Fix acceleration / movement code issues, added race finished state, added checkpoints, added victory animation. --- assets/TestLevel.tmx | 42 +++++++++---------- assets/checkpoint.png | Bin 0 -> 3023 bytes assets/gametiles.png | Bin 57247 -> 60081 bytes assets/gametiles.xcf | Bin 429632 -> 440886 bytes src/AnimationState.h | 51 +++++++++++++++++++++++ src/Checkpoint.cpp | 85 +++++++++++++++++++++++++++++++++++++++ src/Checkpoint.h | 69 +++++++++++++++++++++++++++++++ src/Hamster.cpp | 67 +++++++++++++++++++++--------- src/Hamster.h | 8 +++- src/HamsterGame.cpp | 56 ++++++++++++++++---------- src/HamsterGame.h | 23 ++++------- src/HamsterJet.cpp | 6 +-- src/olcUTIL_Geometry2D.h | 2 - 13 files changed, 326 insertions(+), 83 deletions(-) create mode 100644 assets/checkpoint.png create mode 100644 src/AnimationState.h create mode 100644 src/Checkpoint.cpp create mode 100644 src/Checkpoint.h diff --git a/assets/TestLevel.tmx b/assets/TestLevel.tmx index f5a400d..b893748 100644 --- a/assets/TestLevel.tmx +++ b/assets/TestLevel.tmx @@ -240,13 +240,13 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1485,1486,1487,1488,1489,1490,1491,1492,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1513,1514,1515,1516,1517,1518,1519,1520,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1541,1542,1543,1544,1545,1546,1547,1548,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1569,1570,1571,1572,1573,1574,1575,1576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1597,1598,1599,1600,1601,1602,1603,1604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1625,1626,1627,1628,1629,1630,1631,1632,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1653,1654,1655,1656,1657,1658,1659,1660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1450,1451,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -260,23 +260,23 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1485,1486,1487,1488,1489,1490,1491,1492,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1513,1514,1515,1516,1517,1518,1519,1520,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1541,1542,1543,1544,1545,1546,1547,1548,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1569,1570,1571,1572,1573,1574,1575,1576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1597,1598,1599,1600,1601,1602,1603,1604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1625,1626,1627,1628,1629,1630,1631,1632,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1653,1654,1655,1656,1657,1658,1659,1660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1485,1486,1487,1488,1489,1490,1491,1492,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1513,1514,1515,1516,1517,1518,1519,1520,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1541,1542,1543,1544,1545,1546,1547,1548,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1569,1570,1571,1572,1573,1574,1575,1576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1597,1598,1599,1600,1601,1602,1603,1604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1625,1626,1627,1628,1629,1630,1631,1632,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1653,1654,1655,1656,1657,1658,1659,1660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, diff --git a/assets/checkpoint.png b/assets/checkpoint.png new file mode 100644 index 0000000000000000000000000000000000000000..ad7b66e37c474cbdb38a4fe630b32af4d82e52eb GIT binary patch literal 3023 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 literal 0 HcmV?d00001 diff --git a/assets/gametiles.png b/assets/gametiles.png index 724c5d2b8d629ee26b64220c611172b72b9b5ada..535b28df73ce7803e2c6819990be4da87aef0f5e 100644 GIT binary patch delta 22624 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 delta 19866 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 F_8-3|#8&_S diff --git a/assets/gametiles.xcf b/assets/gametiles.xcf index dab4bce287fd7024f510fe2d58a15c49a1d52afe..50ac492ac83a79619c72d4e44bb613761713b843 100644 GIT binary patch delta 12386 zcmd^_e~cXGS;ya*ot@p=nf-ZtKCgXycfPx|&p!KnzPs3oA*B%h;E##`QYw`{P$Ptd zL?%>&B9aJops7MdA&>_3_|cZO6QW8+gkphXeyBlFQzSq{{Adlb)Uq9-B9LNLNonJ2 zhR^f7v%9x8q?H2dA6R<*JnuX6{`!7rzR$eR-t!+h^2e_p`L#Lcr6&)acIG~P&#Sx6 zOPBAwBXp9Nj4>XCf9D@j|8T!;_}AaH_LaX@>r|hzcI6A!-fcTN_tkCvXWwq^Cw{`( zzi_Pm%JXVn$ByH!9<}xF{kXO7dZ)EN^S5?>_woB|!_#($?w=j9^)K9M?Tv=olK+^s z%l~5S`P|xfX4b|hto=~c+TXuw?TdeI?U!D)_I0~ZZ`RTM8*jCu7rZkMS$pS-wfFs& zwGaJ*wI6)O+E13OeRkE_tAB6pXD(U$ISaM-kDsyi&llqkEoI(+e9gAsOzc4A$_v_1 zp0z70FWH5aPk++3@3ySH_%UnWZXqw<^Fdp`_b07=w;EG^z&=CehyTd7|I)u(`x|!R z@^2Q`lV?6^FI;(twJ%!E%YS#jt$*>NwJ#R~z5H2Qf8`Bp|MM}mzH1*kzh&?9`#){l z2hUr(`I@yCpSJd%Usap<_paH7A1j{n$nL~{XvwxeVi)4Sw`c3``zLFECA9X#e`W1& z|DLrU|0!!f@t4*<^EqoT*|)?0!ymNu=RPm?`;GtH%SD5Q#=mNz@vpwkwqJd)u+J1$ zI~xCL(eLWl9((exUwrZ|hvHI76pvEA^5k9q{oj+6yT%{hVQRx|(->}=_He^=hbPVa z@VMy>*UZu3idmrahs$PZxMY@xeRJ$USs5NR)nUyvv6W%n)Up21H8Z(uLi{p*fFIy{ z_;vi6`i^PhCqA9RVTp^5Y2}V74XZ4`!`ixw-y4>VJFYt{=+?S#90qUFU+luLVsdPQ z3B>jpGiMH2h{HIG!x^o!$V8n*b|4-7yvi;E^}W2pPD3UR%<8ab2E%!CV%RmOhHZ03 zOUrByo93*RhS?fQshe{{#WVxc3`{dH&A>DR(+o^AFwMY}($AJnvXlX82B-(hN(QJI zpkgZ-pknDR)1vO;_cAcdP#C!Z zhZSkVfjXcvc$4d57cxM_Hkd$cpFwjbk%c()U(5iNx-3%cA{&r?{&g_Tz!cxR4yGBH zQeVx$G)n+A1Jn#qwE$`cs9FFtlLDxjf|>(r4yZYx=75?5Y7VG5pyq%|>E}GCIhf{P zdZ4W2V48y|wvvM>)))R~ZU8EkG7m?9AK-iVb^Mz8fQs+aDa-+thpcr2P?``MXVx2#!8XtuS;^`tyNa4r-Ab`}9+8$-4+7BIFlJXQ$UA_BH}K)@Cf zvoc&jy=th~QPiuBiXBCetb+OY0lo-F8NY@v3g#guA@_>XiRehZi^z;bOX@v@Yb07F z`~`$(RCf_DTTezRCk8T)&x+xkVpXhyYFTv)054~p_x`lwX&1N!e6$;iY6s&=Q)s4cM0jp{lux7xT0qa=9fHebF zG;ApYR?0-e7R*WpswhAeS*r5_SFj-pAnM@b2l%2KNtsHGifEXJY=qn_S|_q2^)50q z(k-d?&@PcHt82iDKdQS(*zI)?;U3XNCj(W+p2%1wL8q*~1=oR-$rhPJZkW+Ju+rvh zXJADGJ@rMufE6tppkpU8U`58PgaK;?s)dYM2?JF&rl{tisv-uec`|wFtcuwe&#D-( z=D<2uF<{Ms6%DBJGS+z)D%cRtMIU^84Yl}X{2J{dVjj;&$i4Dxi10|g%e$t+l@tv< z)N7<%CHw`R>QUWA#crES4=dM1oPrym$z+T2kW!z~I;hg-(>HP0 z%`x77PX`hO16JN{krd4rP)iSj1O6w8-Q%;gNeDuY{xtKT?6X#;$T+DuA;#^Fei-~iTe$0!<*=ac@&K)Q# zF>x*?&S5JtaSrRp0DqG(hhN4I@B@4gzm8v1A2M$e4}Cg?F>x;DCA&$Si-~hFajvMl z_`R4oH?9-sZmSdL7`#b;u?sO_4%=Wdv3;(Gm#sJbL>Dm`ZtMl zF>wyxyGfjjiF4FfV}ejj(20q2F>y`{aV~C}7Ly&q*4fBx+`u+X2OGq*T&rWt#^0}k zQ2t>3!})_H^YyPjas2qz<5#bG$FKa&qyDcKEJUyn!9oNJ5iCTo5WzwO3lS_(`VlNd zun@t*fwB_8LIexgN(2j7KZ1ozuz+925AXwg55JCIQy&&C2@7-zBUp%F;SwxFun@sQ zQFrls5iE@Buy9))78txqf3XV@EMOZGff`tecsINw_5WzwO3lS`6frSVbnCuX?&PHY@#n4nXb!bA!a*I*)ri4-P^x{KdS zVPaf|iQDQh!Qf5$i(N=z0^49Rv3y01Urz9{xz6LVFKT~ z1`{bvP+v`9B87<*CQ_Kt0uw1rFxeq&osG<luUnZ!pHV`BErU*)6(%PuO$BaEejDWsFcD&1Pc)?jHMJ7B3MuZ6vPpnDl#adQNe}?j!34DAK;5pmGNu%BAFf{6>_ggYa%iy4P9hyB$HC_A(bPU zEa5L8b)&kA3f*1@Y3@OXu^`Ui6WIiDu89%`*8rHg7MX+VJonlF;xzi&8N`u6PkoU~ z5Jx%($mR)T^AxgaB@@I`5a-?&GC9kRtXztGf;f^HV4E_oAkOvMKR%Oh`|I=n=Hqkw z+y43-e|%nUo&2cd)UW)(`~8oJz4vi!nM8Why8I)XzeCgIubx%&p>vNG7xq5=%YN+C zpL%&m{(skQoYe2;eq-t!zAGHWL(asZX;C_yG8-I4JGA?pg+u%{XW)P%Y`}4~%`vvk z@mBoZaUm5zqHa=14{*et6jBC^H!0*&CKc=NFwrKHZ!wX}hxs-WIaq0ziDa-zAMzra z;FCpG%sM4tkppa<{)4H>NpKWx724%mDPgtiIC8o_gD{42k4yVipr_c`VKF8uD zq|)XL9B_mUIDEG`#yW z<$_EkgG~mI6ds=?x=LWh1}t)btuw%2YI0yL+A6fmwGxY6$I9XU489!Zm*hZ?zs8x` zWxllxRI>zFS-=j^Y-<5l%^ylW5m+-|&45)G1FRXaGQd2~Lz@$4m(rqiIAu0Cg?4E7 zIoO5xZ9YjP?-FoYZFBHzb0`#lcU(Yp@9W?2`U%j{@y&`Pw&W>`*MRP9O!$dB~ zBr?c!C;6E|GJv9PvdDqTu-FnRN9scR*vX|Wq%P_vD!0x8<@cF0^l`DxLf{T&aN7hCc4i^e1O4s1ko#nL- zQ8=G#9egWrpvt=+paoXw*l;0o$wb|N6``1@8#_ZxCgKD-3_4v{xatM4k_6o1xX+&-#OMsQtoXmg~m6LQ+8^JhSD4Zx=0|A;v za6%N$=UNBfDjcx#E(Bk9iB`gZ69pUjz{;eXTyx0+Zebmg ze%nlJMFd!H=_g4(NdSuK$sz|T!(u^|`oRTAo8;?6^nP5_Zyhy~A8F3e$;C>dUX;(F z-31Z(Awv}K9J{m12dw($^RUt`lS{Tyr1~`Kw}JY}Vov6unjhYK_jBG{a&QGx5EMI^ zmOcM~M!hxplZ+$3q9hFXhGFL;IlXnhgY^+3qcxA{9MLNv2mo)kd7D0~>{mGZg(gTi ztyamUHKc++!-WQi%79bq4DIzPzsAwn=l&Vm#fQ}WTHzC^_CxjS97G!=1RI5I#;=?G zePi~U%sE3LYVOO~bH=n1PQD)fS{y`Y@pJqRewPF3EOuUVfjn5)3*VybuvR(rZpj4X z8n-!7J6LJoWxeMaZ!!jvk;8IwN;W}Rrw9N8Y@GoH+$o1B=HTKpELX=Rqf?JT}Bi{IrCJd2&z{9*#a zI2XP}*Ecu5G-2lv{FdMSV@fY~s{x`f{GK#h% zd+X=#TZ=oRICB^A=R5Q1-9%w4Mb5E-dREovgNF8*{jw;c#E~i$A3wOopP_?K?6Gmj zCtg`U3o(LBvJM>F=&GrBs(}6^F>7rY9g^pErQiRJ(XG% zut7W2qKGg{yE2P(Py3eHB-A*=`yuLai?Bbi9;f_BWkr;P^$`FP>bJTUZ~Z$ zBS~1vBui3u9y=X6Dkho45$NKk3oLX;l^JTu1aHyikon!#cBs`sM)z8~g{n&ySYnUF zpaEedPz$rzar~k0fRGTX)ew|uylJs&`N`169;hvRi9Zh4q`i;r5_cBZT^rliRI;=~ zEg>afVDaUr#;W=tLhNzzm+0dIE!kd4SxfeJ9y=X6V21YT0<)^jFiXaHi|bB8ig{a9nZ@ktAk&?;Scs&XCH6=R z8W2YUwNQ&4#U8N(LPDt4#-KSuNQ*_wPmtoz(bp|}2|o_k61mXF=@NGq*j*dj*POMq zLoG2SU|{j(x67*fAVTbM@t5f1v-l;@sBwLnzGsO+5@b&kgEojkvVoH+%o2m-)G#_h zaH80I&vRb+|J|{Or(RRvg?;La4V4L07;LhN2kwm%bJWGGhSSb9pOj#KO`4YD(U|?5x;dxH-_i;HtB@N z??BSyznN(7#>4)xy>CA3x3>6G<1ZQGd`17{*qHZV?cc5&BYzYBXwklay<7bM0tUKO AZU6uP delta 999 zcmXZaOK1~89LMpU&F<)-(AuhpS{jKIAM~L%i5d%~1P_9?f!HFVRPi8U4@PTg5DZvj zi;vh4FcDu7p#_DAu5_s$%*866d|*Kk6(vDM2!V*NL*49m7iK^6`_Jy|?C#7|8uQm0 zCzpv(a(Sy*dOuk4ijc9{S0iE}MNu@XS%*JrBNKIwO^$0Ey|(sA=3{Btbbuyx4>Tp26Jz=C^M1UQ!kmG#2l2^Pe8#8N-u98_oq0d+C;vE$ ze`8FfFACcQy`Gin?pku|M(oUDpdGvUtjw>txdc^%nMmY>$%zY+@O7+c_+IA2P5n zheN!H9A?+bQ5GVjg7GN7LY~?|9&;8jULjvF#zbIT1ccR8tGTSESxq-ZKpyB$f0>nT z^WAAVEz}Oh{2q5Y|0b+Xy2q_|rH=-5Y1Ukn31N)1_*`mCGiuj<)GW + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions or derivations of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions or derivative works in binary form must reproduce the above +copyright notice. This list of conditions and the following disclaimer must be +reproduced in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may +be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +Portions of this software are copyright © 2024 The FreeType +Project (www.freetype.org). Please see LICENSE_FT.txt for more information. +All rights reserved. +*/ +#pragma endregion +#pragma once +namespace AnimationState{ + enum AnimationState{ + DEFAULT, + WHEEL_TOP, + WHEEL_BOTTOM, + JET_LIGHTS, + JET_FLAMES, + KNOCKOUT, + CHECKPOINT_CYCLING, + CHECKPOINT_COLLECTED, + SIDE_VIEW, + }; +} \ No newline at end of file diff --git a/src/Checkpoint.cpp b/src/Checkpoint.cpp new file mode 100644 index 0000000..c999055 --- /dev/null +++ b/src/Checkpoint.cpp @@ -0,0 +1,85 @@ +#pragma region License +/* +License (OLC-3) +~~~~~~~~~~~~~~~ + +Copyright 2024 Joshua Sigona + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions or derivations of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions or derivative works in binary form must reproduce the above +copyright notice. This list of conditions and the following disclaimer must be +reproduced in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may +be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +Portions of this software are copyright © 2024 The FreeType +Project (www.freetype.org). Please see LICENSE_FT.txt for more information. +All rights reserved. +*/ +#pragma endregion + +#include "Checkpoint.h" +#include "HamsterGame.h" +std::vectorCheckpoint::checkpoints; +Checkpoint::Checkpoint(const vf2d pos) +:pos(pos){ + animation.AddState(AnimationState::DEFAULT,HamsterGame::GetAnimation("checkpoint.png",AnimationState::DEFAULT)); + animation.AddState(AnimationState::CHECKPOINT_COLLECTED,HamsterGame::GetAnimation("checkpoint.png",AnimationState::CHECKPOINT_COLLECTED)); + animation.AddState(AnimationState::CHECKPOINT_CYCLING,HamsterGame::GetAnimation("checkpoint.png",AnimationState::CHECKPOINT_CYCLING)); +} +void Checkpoint::Initialize(const std::vector&checkpointPositions){ + checkpoints.clear(); + for(const vf2d&checkpointPos:checkpointPositions){ + checkpoints.emplace_back(checkpointPos); + } +} +void Checkpoint::UpdateCheckpoints(const float fElapsedTime){ + for(Checkpoint&checkpoint:checkpoints){ + checkpoint.animation.UpdateState(checkpoint.internal_animState,fElapsedTime); + if(checkpoint.collectedByPlayerTimer>0.f){ + checkpoint.collectedByPlayerTimer-=fElapsedTime; + if(checkpoint.collectedByPlayerTimer<=0.f){ + checkpoint.animation.ChangeState(checkpoint.internal_animState,AnimationState::CHECKPOINT_COLLECTED); + } + } + } +} +void Checkpoint::DrawCheckpoints(TransformedView&tv){ + for(Checkpoint&checkpoint:checkpoints){ + const Animate2D::Frame&frame{checkpoint.animation.GetFrame(checkpoint.internal_animState)}; + if(checkpoint.animation.GetState(checkpoint.internal_animState)!=AnimationState::DEFAULT){ + HamsterGame::Game().SetDecalMode(DecalMode::ADDITIVE); + tv.DrawPartialRotatedDecal(checkpoint.pos,frame.GetSourceImage()->Decal(),0.f,frame.GetSourceRect().size/2,frame.GetSourceRect().pos,frame.GetSourceRect().size,{1.1f,1.1f}); + HamsterGame::Game().SetDecalMode(DecalMode::NORMAL); + } + tv.DrawPartialRotatedDecal(checkpoint.pos,frame.GetSourceImage()->Decal(),0.f,frame.GetSourceRect().size/2,frame.GetSourceRect().pos,frame.GetSourceRect().size); + } +} +std::vector&Checkpoint::GetCheckpoints(){ + return checkpoints; +} +const vf2d&Checkpoint::GetPos()const{ + return pos; +} +void Checkpoint::OnCheckpointCollect(){ + collectedByPlayerTimer=2.f; + animation.ChangeState(internal_animState,AnimationState::CHECKPOINT_CYCLING); +} \ No newline at end of file diff --git a/src/Checkpoint.h b/src/Checkpoint.h new file mode 100644 index 0000000..f82f7e4 --- /dev/null +++ b/src/Checkpoint.h @@ -0,0 +1,69 @@ +#pragma region License +/* +License (OLC-3) +~~~~~~~~~~~~~~~ + +Copyright 2024 Joshua Sigona + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions or derivations of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions or derivative works in binary form must reproduce the above +copyright notice. This list of conditions and the following disclaimer must be +reproduced in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may +be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +Portions of this software are copyright © 2024 The FreeType +Project (www.freetype.org). Please see LICENSE_FT.txt for more information. +All rights reserved. +*/ +#pragma endregion +#pragma once +#include "olcUTIL_Geometry2D.h" +#include "olcPGEX_TransformedView.h" +#include "olcUTIL_Animate2D.h" +#include "AnimationState.h" + +class Checkpoint{ + friend struct std::hash; + vf2d pos{}; + float collectedByPlayerTimer{}; + Animate2D::Animationanimation; + Animate2D::AnimationState internal_animState; + static std::vectorcheckpoints; +public: + Checkpoint(const vf2d pos); + static void Initialize(const std::vector&checkpointPositions); + static void UpdateCheckpoints(const float fElapsedTime); + static void DrawCheckpoints(TransformedView&tv); + static std::vector&GetCheckpoints(); + const vf2d&GetPos()const; + void OnCheckpointCollect(); + friend const bool operator==(const Checkpoint&cp1,const Checkpoint&cp2){return cp1.pos==cp2.pos;} +}; + +template <> +struct std::hash +{ + std::size_t operator()(const Checkpoint&checkpoint)const + { + return std::hash()((((int_fast64_t)(*(int_fast32_t*)(&checkpoint.pos.x))<<32)|*(int_fast32_t*)(&checkpoint.pos.y))); + } +}; \ No newline at end of file diff --git a/src/Hamster.cpp b/src/Hamster.cpp index 701ccf9..1cb52a8 100644 --- a/src/Hamster.cpp +++ b/src/Hamster.cpp @@ -40,6 +40,7 @@ All rights reserved. #include "Hamster.h" #include "util.h" #include +#include "AnimationState.h" std::vectorHamster::HAMSTER_LIST; const uint8_t Hamster::MAX_HAMSTER_COUNT{100U}; @@ -53,7 +54,7 @@ std::optionalHamster::playerHamster; Hamster::Hamster(const vf2d spawnPos,const std::string&img,const PlayerControlled IsPlayerControlled) :pos(spawnPos),IsPlayerControlled(IsPlayerControlled){ animations=HamsterGame::GetAnimations(img); - animations.ChangeState(internalAnimState,HamsterGame::DEFAULT); + animations.ChangeState(internalAnimState,AnimationState::DEFAULT); } void Hamster::UpdateHamsters(const float fElapsedTime){ @@ -65,7 +66,7 @@ void Hamster::UpdateHamsters(const float fElapsedTime){ h.HandleCollision(); switch(h.state){ case NORMAL:{ - if(h.bumpTimer<=0.f){ + if(h.bumpTimer<=0.f&&!h.CollectedAllCheckpoints()){ if(h.IsPlayerControlled){ h.HandlePlayerControls(); }else{ @@ -114,7 +115,7 @@ void Hamster::UpdateHamsters(const float fElapsedTime){ h.knockoutTimer-=fElapsedTime; if(h.knockoutTimer<=0.f){ h.SetState(NORMAL); - h.animations.ChangeState(h.internalAnimState,HamsterGame::DEFAULT); + h.animations.ChangeState(h.internalAnimState,AnimationState::DEFAULT); } }break; } @@ -143,6 +144,10 @@ void Hamster::UpdateHamsters(const float fElapsedTime){ h.readyFlashTimer+=fElapsedTime; h.jetFuelDisplayAmt+=(h.jetFuel-h.jetFuelDisplayAmt)*4.f*fElapsedTime; } + if(h.CollectedAllCheckpoints()){ + h.animations.ChangeState(h.internalAnimState,AnimationState::SIDE_VIEW); + h.raceFinishAnimTimer+=fElapsedTime; + } } } @@ -162,19 +167,33 @@ void Hamster::LoadHamsters(const vf2d startingLoc){ void Hamster::DrawHamsters(TransformedView&tv){ for(Hamster&h:HAMSTER_LIST){ const Animate2D::FrameSequence&anim{h.animations.GetFrames(h.internalAnimState)}; - const Animate2D::FrameSequence&wheelTopAnim{h.animations.GetFrames(HamsterGame::WHEEL_TOP)}; - const Animate2D::FrameSequence&wheelBottomAnim{h.animations.GetFrames(HamsterGame::WHEEL_BOTTOM)}; - const Animate2D::Frame&img{h.animations.GetState(h.internalAnimState)==HamsterGame::DEFAULT?anim.GetFrame(h.distanceTravelled/100.f):h.GetCurrentAnimation()}; + const Animate2D::FrameSequence&wheelTopAnim{h.animations.GetFrames(AnimationState::WHEEL_TOP)}; + const Animate2D::FrameSequence&wheelBottomAnim{h.animations.GetFrames(AnimationState::WHEEL_BOTTOM)}; + const Animate2D::Frame&img{h.animations.GetState(h.internalAnimState)==AnimationState::DEFAULT?anim.GetFrame(h.distanceTravelled/100.f):h.GetCurrentAnimation()}; const Animate2D::Frame&wheelTopImg{wheelTopAnim.GetFrame(h.distanceTravelled/80.f)}; const Animate2D::Frame&wheelBottomImg{wheelBottomAnim.GetFrame(h.distanceTravelled/80.f)}; - if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(); - HamsterGame::Game().SetZ(h.z); - if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},wheelBottomImg.GetSourceImage()->Decal(),h.rot,wheelBottomImg.GetSourceRect().size/2,wheelBottomImg.GetSourceRect().pos,wheelBottomImg.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); - HamsterGame::Game().SetZ(h.z+0.005f); - tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},img.GetSourceImage()->Decal(),h.rot,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); - HamsterGame::Game().SetZ(h.z+0.01f); - if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},wheelTopImg.GetSourceImage()->Decal(),h.rot,wheelTopImg.GetSourceRect().size/2,wheelTopImg.GetSourceRect().pos,wheelTopImg.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,{255,255,255,192},h.imgScale)); - HamsterGame::Game().SetZ(0.f); + if(h.CollectedAllCheckpoints()){ + float animCycle{fmod(h.raceFinishAnimTimer,1.5f)}; + float facingXScale{fmod(h.raceFinishAnimTimer,3.f)>=1.5f?-1.f:1.f}; + float yHopAmt{0.f}; + if(animCycle>=0.8f){ + yHopAmt=-abs(sin(geom2d::pi*(animCycle/0.35f)))*12.f; + } + if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(); + HamsterGame::Game().SetZ(h.z); + tv.DrawRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},HamsterGame::GetGFX("shadow.png").Decal(),0.f,HamsterGame::GetGFX("shadow.png").Sprite()->Size()/2); + HamsterGame::Game().SetZ(h.z+0.005f); + tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY+yHopAmt},img.GetSourceImage()->Decal(),0.f,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale*vf2d{facingXScale,1.f},PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); + HamsterGame::Game().SetZ(h.z); + }else{ + if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(); + HamsterGame::Game().SetZ(h.z); + if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},wheelBottomImg.GetSourceImage()->Decal(),h.rot,wheelBottomImg.GetSourceRect().size/2,wheelBottomImg.GetSourceRect().pos,wheelBottomImg.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); + tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},img.GetSourceImage()->Decal(),h.rot,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); + HamsterGame::Game().SetZ(h.z+0.01f); + if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},wheelTopImg.GetSourceImage()->Decal(),h.rot,wheelTopImg.GetSourceRect().size/2,wheelTopImg.GetSourceRect().pos,wheelTopImg.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,{255,255,255,192},h.imgScale)); + HamsterGame::Game().SetZ(0.f); + } } } @@ -185,7 +204,7 @@ void Hamster::DrawOverlay(){ Pixel jetDisplayCol{VERY_DARK_GREY}; if(!GetPlayer().hamsterJet.has_value()){ if(GetPlayer().HasPowerup(Powerup::JET))jetDisplayCol=WHITE; - const Animate2D::FrameSequence&lightAnim{HamsterGame::Game().GetAnimation("hamster_jet.png",HamsterGame::AnimationState::JET_LIGHTS)}; + const Animate2D::FrameSequence&lightAnim{HamsterGame::Game().GetAnimation("hamster_jet.png",AnimationState::JET_LIGHTS)}; const Animate2D::Frame&lightFrame{lightAnim.GetFrame(HamsterGame::Game().GetRuntime())}; HamsterGame::Game().DrawPartialRotatedDecal(jetDisplayOffset+vf2d{48.f,80.f},GetPlayer().hamsterJetDisplay.Decal(),0.f,{24.f,24.f},{0.f,0.f},{48.f,48.f},{2.f,2.f},jetDisplayCol); HamsterGame::Game().DrawPartialRotatedDecal(jetDisplayOffset+vf2d{48.f,80.f},GetPlayer().hamsterJetLightsDisplay.Decal(),0.f,{24.f,24.f},lightFrame.GetSourceRect().pos,lightFrame.GetSourceRect().size,{2.f,2.f},jetDisplayCol); @@ -254,7 +273,7 @@ void Hamster::HandlePlayerControls(){ if(aimingDir!=vf2d{}){ targetRot=aimingDir.norm().polar().y; const vf2d currentVel{vel}; - vel+=vf2d{currentVel.polar().x+(GetMaxSpeed()*HamsterGame::Game().GetElapsedTime())/GetTimeToMaxSpeed(),rot}.cart(); + vel=vf2d{currentVel.polar().x+((GetMaxSpeed()/GetTimeToMaxSpeed())*HamsterGame::Game().GetElapsedTime()),rot}.cart(); vel=vf2d{std::min(GetMaxSpeed(),vel.polar().x),vel.polar().y}.cart(); frictionEnabled=false; } @@ -329,6 +348,12 @@ void Hamster::HandleCollision(){ powerup.OnPowerupObtain(*this); } } + for(Checkpoint&checkpoint:Checkpoint::GetCheckpoints()){ + if(z<=0.1f&&geom2d::overlaps(geom2d::rect(checkpoint.GetPos()-vf2d{62,60},{122.f,113.f}),geom2d::circle(GetPos(),collisionRadius))&&!checkpointsCollected.count(checkpoint)){ + checkpointsCollected.insert(checkpoint); + checkpoint.OnCheckpointCollect(); + } + } } const float Hamster::GetRadius()const{ @@ -353,8 +378,8 @@ const float Hamster::GetTimeToMaxSpeed()const{ if(!HasPowerup(Powerup::ICE)&&GetTerrainStandingOn()==Terrain::ICE)finalTimeToMaxSpd*=3; else if(!HasPowerup(Powerup::SWAMP)&&GetTerrainStandingOn()==Terrain::SWAMP)finalTimeToMaxSpd*=1.25; if(hamsterJet.has_value()){ - if(hamsterJet.value().GetState()==HamsterJet::LANDING)finalTimeToMaxSpd*=5.f; - else if(state==FLYING)finalTimeToMaxSpd*=30.f; + if(hamsterJet.value().GetState()==HamsterJet::LANDING)finalTimeToMaxSpd*=2.f; + else if(state==FLYING)finalTimeToMaxSpd*=3.f; } return finalTimeToMaxSpd; } @@ -534,7 +559,7 @@ void Hamster::SetJetFuel(const float amt){ void Hamster::Knockout(){ SetState(KNOCKOUT); knockoutTimer=4.f; - animations.ChangeState(internalAnimState,HamsterGame::KNOCKOUT); + animations.ChangeState(internalAnimState,AnimationState::KNOCKOUT); } const float Hamster::GetSpeed()const{ @@ -543,4 +568,8 @@ const float Hamster::GetSpeed()const{ void Hamster::SetState(const HamsterState state){ this->state=state; +} + +const bool Hamster::CollectedAllCheckpoints()const{ + return checkpointsCollected.size()==Checkpoint::GetCheckpoints().size(); } \ No newline at end of file diff --git a/src/Hamster.h b/src/Hamster.h index 703566b..8352419 100644 --- a/src/Hamster.h +++ b/src/Hamster.h @@ -44,6 +44,7 @@ All rights reserved. #include #include "HamsterJet.h" #include "HamsterGame.h" +#include "Checkpoint.h" class Hamster{ friend class HamsterJet; @@ -71,7 +72,7 @@ class Hamster{ static const std::string PLAYER_HAMSTER_IMAGE; const float DEFAULT_MAX_SPD{128.f}; - const float DEFAULT_TIME_TO_MAX_SPD{0.5f}; + const float DEFAULT_TIME_TO_MAX_SPD{0.3f}; const float DEFAULT_FRICTION{400.f}; const float DEFAULT_TURN_SPD{2.f*geom2d::pi}; const float DEFAULT_BUMP_AMT{100.f}; @@ -95,7 +96,7 @@ class Hamster{ float imgScale{1.f}; Pixel shrinkEffectColor{BLACK}; std::string img; - Animate2D::Animationanimations; + Animate2D::Animationanimations; Animate2D::AnimationState internalAnimState; PlayerControlled IsPlayerControlled; static std::optionalplayerHamster; @@ -110,6 +111,8 @@ class Hamster{ float jetFuel{0.f}; float jetFuelDisplayAmt{0.f}; float knockoutTimer{0.f}; + std::unordered_setcheckpointsCollected; + float raceFinishAnimTimer{0.f}; public: Hamster(const vf2d spawnPos,const std::string&img,const PlayerControlled IsPlayerControlled=NPC); static const Hamster&GetPlayer(); @@ -151,4 +154,5 @@ public: const float GetSpeed()const; const Terrain::TerrainType GetTerrainHoveringOver()const; void SetState(const HamsterState state); + const bool CollectedAllCheckpoints()const; }; \ No newline at end of file diff --git a/src/HamsterGame.cpp b/src/HamsterGame.cpp index 12bcb3b..94be077 100644 --- a/src/HamsterGame.cpp +++ b/src/HamsterGame.cpp @@ -3,16 +3,17 @@ #include #include #include "util.h" +#include "Checkpoint.h" geom2d::rectHamsterGame::SCREEN_FRAME{{96,0},{320,288}}; -std::unordered_map>HamsterGame::ANIMATIONS; +std::unordered_map>HamsterGame::ANIMATIONS; std::unordered_mapHamsterGame::GFX; const std::string HamsterGame::ASSETS_DIR{"assets/"}; HamsterGame*HamsterGame::self{nullptr}; std::unordered_mapHamsterGame::ANIMATED_TILE_IDS; -HamsterGame::HamsterGame(){ - sAppName = "Project Hamster"; +HamsterGame::HamsterGame(const std::string&appName){ + sAppName=appName; HamsterGame::self=this; } @@ -32,9 +33,9 @@ bool HamsterGame::OnUserCreate(){ return true; } -void HamsterGame::_LoadImage(const std::string_view img){ - GFX.insert({std::string(img),Renderable{}}); - rcode result{GFX[std::string(img)].Load(ASSETS_DIR+std::string(img),nullptr,false,false)}; +void HamsterGame::_LoadImage(const std::string&img){ + GFX.insert({img,Renderable{}}); + rcode result{GFX[img].Load(ASSETS_DIR+img,nullptr,false,false)}; if(result!=OK)throw std::runtime_error{std::format("Failed to Load Image {}. OLC Rcode: {}",img,int(result))}; } @@ -60,13 +61,13 @@ void HamsterGame::LoadGraphics(){ void HamsterGame::LoadAnimations(){ auto LoadImageIfRequired=[this](const std::string&img){if(!GFX.count(std::string(img)))_LoadImage(img);}; - auto LoadStillAnimation=[this,&LoadImageIfRequired](const AnimationState state,const std::string&img){ + auto LoadStillAnimation=[this,&LoadImageIfRequired](const AnimationState::AnimationState state,const std::string&img){ Animate2D::FrameSequence stillAnimation{0.f,Animate2D::Style::OneShot}; LoadImageIfRequired(img); stillAnimation.AddFrame(Animate2D::Frame{&GetGFX(img),{{},GetGFX(img).Sprite()->Size()}}); ANIMATIONS[std::string(img)].AddState(state,stillAnimation); }; - auto LoadAnimation=[this,&LoadImageIfRequired](const AnimationState state,const std::string&img,const std::vectorframes,const float frameDuration=0.1f,const Animate2D::Style style=Animate2D::Style::Repeat,vf2d frameSize={32,32}){ + auto LoadAnimation=[this,&LoadImageIfRequired](const AnimationState::AnimationState state,const std::string&img,const std::vectorframes,const float frameDuration=0.1f,const Animate2D::Style style=Animate2D::Style::Repeat,vf2d frameSize={32,32}){ Animate2D::FrameSequence newAnimation{frameDuration,style}; LoadImageIfRequired(img); for(const vf2d&framePos:frames){ @@ -75,10 +76,11 @@ void HamsterGame::LoadAnimations(){ ANIMATIONS[std::string(img)].AddState(state,newAnimation); }; - LoadAnimation(DEFAULT,"hamster.png",{{0,32},{32,32}},0.3f); - LoadAnimation(WHEEL_TOP,"hamster.png",{{0,96},{32,96}},0.1f); - LoadAnimation(WHEEL_BOTTOM,"hamster.png",{{64,96},{96,96}},0.1f); - LoadAnimation(KNOCKOUT,"hamster.png",{{64,32},{96,32}},0.2f); + LoadAnimation(AnimationState::DEFAULT,"hamster.png",{{0,32},{32,32}},0.3f); + LoadAnimation(AnimationState::WHEEL_TOP,"hamster.png",{{0,96},{32,96}},0.1f); + LoadAnimation(AnimationState::WHEEL_BOTTOM,"hamster.png",{{64,96},{96,96}},0.1f); + LoadAnimation(AnimationState::KNOCKOUT,"hamster.png",{{64,32},{96,32}},0.2f); + LoadAnimation(AnimationState::SIDE_VIEW,"hamster.png",{{0,0},{32,0}},0.3f); Animate2D::FrameSequence&waterAnimFrames{(*ANIMATED_TILE_IDS.insert({1384,Animate2D::FrameSequence{0.2f}}).first).second}; for(vf2d&sourcePos:std::vector{{192+16*0,784},{192+16*1,784},{192+16*2,784},{192+16*3,784},{192+16*4,784},{192+16*5,784},{192+16*6,784},{192+16*7,784}}){ waterAnimFrames.AddFrame(Animate2D::Frame{&GetGFX("gametiles.png"),{sourcePos,{16,16}}}); @@ -87,17 +89,19 @@ void HamsterGame::LoadAnimations(){ for(vf2d&sourcePos:std::vector{{192+16*0,800},{192+16*1,800},{192+16*2,800},{192+16*3,800},{192+16*4,800},{192+16*5,800},{192+16*6,800},{192+16*7,800},{192+16*8,800}}){ lavaAnimFrames.AddFrame(Animate2D::Frame{&GetGFX("gametiles.png"),{sourcePos,{16,16}}}); } - LoadAnimation(JET_LIGHTS,"hamster_jet.png",{{0,48},{48,48}},0.3f,Animate2D::Style::Repeat,{48,48}); - LoadAnimation(JET_FLAMES,"hamster_jet.png",{{48,0},{96,0}},0.15f,Animate2D::Style::Repeat,{48,48}); - + LoadAnimation(AnimationState::JET_LIGHTS,"hamster_jet.png",{{0,48},{48,48}},0.3f,Animate2D::Style::Repeat,{48,48}); + LoadAnimation(AnimationState::JET_FLAMES,"hamster_jet.png",{{48,0},{96,0}},0.15f,Animate2D::Style::Repeat,{48,48}); + LoadAnimation(AnimationState::DEFAULT,"checkpoint.png",{{}},0.f,Animate2D::Style::OneShot,{128,128}); + LoadAnimation(AnimationState::CHECKPOINT_CYCLING,"checkpoint.png",{{},{128,0}},0.4f,Animate2D::Style::Repeat,{128,128}); + LoadAnimation(AnimationState::CHECKPOINT_COLLECTED,"checkpoint.png",{{128,0}},0.f,Animate2D::Style::OneShot,{128,128}); animatedWaterTile.Create(16,16,false,false); UpdateWaterTexture(); } -void HamsterGame::LoadLevel(const std::string_view mapName){ +void HamsterGame::LoadLevel(const std::string&mapName){ const vf2d levelSpawnLoc{50,50}; //TEMPORARY - currentMap=TMXParser{ASSETS_DIR+std::string(mapName)}; + currentMap=TMXParser{ASSETS_DIR+mapName}; cloudSpd.x=util::random_range(-12.f,12.f); cloudSpd.y=util::random_range(-0.3f,0.3f); cloudOffset.x=util::random(); @@ -112,14 +116,18 @@ void HamsterGame::LoadLevel(const std::string_view mapName){ Clear(BLANK); SetPixelMode(Pixel::MASK); - #pragma region Detect powerup tiles + #pragma region Detect special tiles + { std::vectormapPowerups; + std::vectorcheckpoints; for(const LayerTag&layer:currentMap.value().GetData().GetLayers()){ for(size_t y:std::ranges::iota_view(0U,layer.tiles.size())){ for(size_t x:std::ranges::iota_view(0U,layer.tiles[y].size())){ const int tileID{layer.tiles[y][x]-1}; if(Powerup::TileIDIsUpperLeftPowerupTile(tileID))mapPowerups.emplace_back(vf2d{float(x),float(y)}*16+vf2d{16,16},Powerup::TileIDPowerupType(tileID)); + if(tileID==1485)checkpoints.emplace_back(vf2d{float(x),float(y)}*16+vf2d{48,64}); + const int numTilesWide{GetGFX("gametiles.png").Sprite()->width/16}; const int numTilesTall{GetGFX("gametiles.png").Sprite()->height/16}; @@ -131,6 +139,8 @@ void HamsterGame::LoadLevel(const std::string_view mapName){ } } Powerup::Initialize(mapPowerups); + Checkpoint::Initialize(checkpoints); + } #pragma endregion mapImage.Decal()->Update(); @@ -150,6 +160,7 @@ void HamsterGame::UpdateGame(const float fElapsedTime){ tv.SetWorldOffset(tv.ScaleToWorld(-SCREEN_FRAME.pos)+camera.GetViewPosition()); Hamster::UpdateHamsters(fElapsedTime); Powerup::UpdatePowerups(fElapsedTime); + Checkpoint::UpdateCheckpoints(fElapsedTime); border.Update(fElapsedTime); } @@ -158,6 +169,7 @@ void HamsterGame::DrawGame(){ tv.DrawPartialDecal({-3200,-3200},currentMap.value().GetData().GetMapData().MapSize*16+vf2d{6400,6400},animatedWaterTile.Decal(),{0,0},currentMap.value().GetData().GetMapData().MapSize*16+vf2d{6400,6400}); SetZ(0.f); DrawLevelTiles(); + Checkpoint::DrawCheckpoints(tv); Powerup::DrawPowerups(tv); Hamster::DrawHamsters(tv); SetZ(3.f); @@ -279,7 +291,7 @@ const Renderable&HamsterGame::GetGFX(const std::string&img){ if(!GFX.count(img))throw std::runtime_error{std::format("Image {} does not exist!",img)}; return GFX[img]; } -const Animate2D::Animation&HamsterGame::GetAnimations(const std::string&img){ +const Animate2D::Animation&HamsterGame::GetAnimations(const std::string&img){ if(!ANIMATIONS.count(img))throw std::runtime_error{std::format("Animations for {} does not exist!",img)}; return ANIMATIONS[img]; } @@ -388,6 +400,7 @@ void HamsterGame::Apply3DTransform(std::vector&decals){ renderer.SetTransform(matWorld); for(DecalInstance&decal:oldDecals){ + SetDecalMode(decal.mode); if(decal.transform==GFX3DTransform::NO_TRANSFORM)foregroundDecals.emplace_back(decal); else if(decal.points==3){ @@ -427,13 +440,14 @@ void HamsterGame::Apply3DTransform(std::vector&decals){ renderer.Render(shadowTris,decal.decal,GFX3D::RENDER_TEXTURED|GFX3D::RENDER_DEPTH); } } + SetDecalMode(DecalMode::NORMAL); } std::sort(decals.begin(),decals.end(),[](const DecalInstance&d1,const DecalInstance&d2){return d1.z[0]>d2.z[0];}); std::copy(foregroundDecals.begin(),foregroundDecals.end(),std::back_inserter(decals)); } -const Animate2D::FrameSequence&HamsterGame::GetAnimation(const std::string&img,const AnimationState state){ +const Animate2D::FrameSequence&HamsterGame::GetAnimation(const std::string&img,const AnimationState::AnimationState state){ return GetAnimations(img).GetFrames(state); } @@ -450,7 +464,7 @@ const bool HamsterGame::IsInBounds(const vf2d pos)const{ int main() { - HamsterGame game; + HamsterGame game("Project Hamster"); if(game.Construct(512, 288, 3, 3)) game.Start(); diff --git a/src/HamsterGame.h b/src/HamsterGame.h index 4a923f6..87d2440 100644 --- a/src/HamsterGame.h +++ b/src/HamsterGame.h @@ -47,6 +47,7 @@ All rights reserved. #include "Terrain.h" #include "SpecialRenderable.h" #include "olcPGEX_Graphics3D.h" +#include "AnimationState.h" struct Letter{ vf2d pos; @@ -58,16 +59,8 @@ class HamsterGame : public olc::PixelGameEngine { const static std::string ASSETS_DIR; public: - enum AnimationState{ - DEFAULT, - WHEEL_TOP, - WHEEL_BOTTOM, - JET_LIGHTS, - JET_FLAMES, - KNOCKOUT, - }; - - HamsterGame(); + HamsterGame()=delete; + HamsterGame(const std::string&appName); static geom2d::rectSCREEN_FRAME; TransformedView tv{}; public: @@ -76,8 +69,8 @@ public: bool OnUserDestroy()override final; static const Renderable&GetGFX(const std::string&img); - static const Animate2D::Animation&GetAnimations(const std::string&img); - static const Animate2D::FrameSequence&GetAnimation(const std::string&img,const AnimationState state); + static const Animate2D::Animation&GetAnimations(const std::string&img); + static const Animate2D::FrameSequence&GetAnimation(const std::string&img,const AnimationState::AnimationState state); static HamsterGame&Game(); static std::unordered_mapANIMATED_TILE_IDS; const double GetRuntime()const; @@ -91,10 +84,10 @@ private: void DrawGame(); void LoadGraphics(); void LoadAnimations(); - void LoadLevel(const std::string_view mapName); - void _LoadImage(const std::string_view img); + void LoadLevel(const std::string&mapName); + void _LoadImage(const std::string&img); static std::unordered_mapGFX; - static std::unordered_map>ANIMATIONS; + static std::unordered_map>ANIMATIONS; static HamsterGame*self; Border border; void DrawLevelTiles(); diff --git a/src/HamsterJet.cpp b/src/HamsterJet.cpp index 5f3f5ce..be08f20 100644 --- a/src/HamsterJet.cpp +++ b/src/HamsterJet.cpp @@ -139,14 +139,14 @@ void HamsterJet::Draw(){ } HamsterGame::Game().SetZ(z); HamsterGame::Game().tv.DrawPartialRotatedDecal(pos+vf2d{0,drawingOffsetY},jet.Decal(),0.f,{24,24},{},{48,48}); - const Animate2D::FrameSequence&flameAnim{HamsterGame::Game().GetAnimation("hamster_jet.png",HamsterGame::AnimationState::JET_FLAMES)}; + const Animate2D::FrameSequence&flameAnim{HamsterGame::Game().GetAnimation("hamster_jet.png",AnimationState::JET_FLAMES)}; const Animate2D::Frame&flameFrame{flameAnim.GetFrame(HamsterGame::Game().GetRuntime())}; HamsterGame::Game().SetZ(z+0.01f); if(jetState[TOP_LEFT])HamsterGame::Game().tv.DrawPartialRotatedDecal(pos+vf2d{0,drawingOffsetY},flameFrame.GetSourceImage()->Decal(),0.f,flameFrame.GetSourceRect().size/2,flameFrame.GetSourceRect().pos+vf2d{0,0},flameFrame.GetSourceRect().size/2); if(jetState[BOTTOM_LEFT])HamsterGame::Game().tv.DrawPartialRotatedDecal(pos+vf2d{0,drawingOffsetY},flameFrame.GetSourceImage()->Decal(),0.f,{24,0},flameFrame.GetSourceRect().pos+vf2d{0,24},flameFrame.GetSourceRect().size/2); if(jetState[BOTTOM_RIGHT])HamsterGame::Game().tv.DrawPartialRotatedDecal(pos+vf2d{0,drawingOffsetY},flameFrame.GetSourceImage()->Decal(),0.f,{0,0},flameFrame.GetSourceRect().pos+vf2d{24,24},flameFrame.GetSourceRect().size/2); if(jetState[TOP_RIGHT])HamsterGame::Game().tv.DrawPartialRotatedDecal(pos+vf2d{0,drawingOffsetY},flameFrame.GetSourceImage()->Decal(),0.f,{0,24},flameFrame.GetSourceRect().pos+vf2d{24,0},flameFrame.GetSourceRect().size/2); - const Animate2D::FrameSequence&lightAnim{HamsterGame::Game().GetAnimation("hamster_jet.png",HamsterGame::AnimationState::JET_LIGHTS)}; + const Animate2D::FrameSequence&lightAnim{HamsterGame::Game().GetAnimation("hamster_jet.png",AnimationState::JET_LIGHTS)}; const Animate2D::Frame&lightFrame{lightAnim.GetFrame(HamsterGame::Game().GetRuntime())}; HamsterGame::Game().SetZ(z+0.02f); HamsterGame::Game().tv.DrawPartialRotatedDecal(pos+vf2d{0,drawingOffsetY},lights.Decal(),0.f,lightFrame.GetSourceRect().size/2.f,lightFrame.GetSourceRect().pos,lightFrame.GetSourceRect().size); @@ -179,7 +179,7 @@ void HamsterJet::HandleJetControls(){ if(aimingDir!=vf2d{}&&hamster.jetFuel>0.f){ hamster.targetRot=aimingDir.norm().polar().y; const vf2d currentVel{hamster.vel}; - hamster.vel+=vf2d{currentVel.polar().x+(hamster.GetMaxSpeed()*HamsterGame::Game().GetElapsedTime())/hamster.GetTimeToMaxSpeed(),hamster.rot}.cart(); + hamster.vel=vf2d{currentVel.polar().x+((hamster.GetMaxSpeed()/hamster.GetTimeToMaxSpeed())*HamsterGame::Game().GetElapsedTime()),hamster.rot}.cart(); hamster.vel=vf2d{std::min(hamster.GetMaxSpeed(),hamster.vel.polar().x),hamster.vel.polar().y}.cart(); hamster.frictionEnabled=false; } diff --git a/src/olcUTIL_Geometry2D.h b/src/olcUTIL_Geometry2D.h index 245bc78..9c93911 100644 --- a/src/olcUTIL_Geometry2D.h +++ b/src/olcUTIL_Geometry2D.h @@ -512,8 +512,6 @@ namespace olc #include "olcPixelGameEngine.h" #endif - - namespace olc::utils::geom2d { // Lemon Meringue