[Feature] Implement seeded runs by adding a Seed selection menu (#482)

* initial commit

* wip

* WIP

* WIP

* clang format

* Choose Seed navigation mostly done

* seed input navigation done

* seed input done

* cleanup and clang format

* Implement base 10 to 36 conversions

* Enable seeded runs

* clang format

* show default deck sprite, name and description

* Rename Deck enum to DeckType

* Implement arbitrary 9-patch expand system

* Make 9-patch example smaller in the docs

* Improve NinePatchRect docs

* fix Deck back side sprite palette

* clang format

* Add last deck description

* clang format

* Fix 'Z' in seed input keyboard

* Fix rebase issue

* fix deck sprite not updating

* Documents static funcs in run_setup.c

* more documentation

* clang format

* Move Play button to the left in its row

* Tests WIP

* removing tests for random.h

* use the new StateMachine struct

* First wave of fixes

* Fix the 9-patch again

* Changed the base 36 logic so it's in big endian

* properly set end of base 36 string to '\0'

* typos

* fix cursor position after rolling a seed + fix random seed generation

* Make keyboard more intuitive to use

* static const var

* Address more comment from @ricfehr3

* clang format

* clang format

* clang format

* clang format

* clang format

* clang format

* clang format

* fix deck palette

* create the `DEF_SEED_KEYBOARD_BUTTON_OBJECT` macro

* Replace `expand_3x3` by a call to `expand_9-patch`

* clang format

* clang format

* clang format

* fix rebase iussue in state_machine.h

---------

Co-authored-by: MathisMartin31 <mathis.martin31@gmail.com>
This commit is contained in:
Geralt
2026-06-02 00:06:37 -07:00
committed by GitHub
co-authored by MathisMartin31
parent 21d8d912ab
commit 1df8402900
32 changed files with 2161 additions and 123 deletions
+91
View File
@@ -191,3 +191,94 @@ uint16_t u16_protected_mult(uint16_t a, uint16_t b)
{
return (a == 0 || b == 0) ? 0 : (a > (UINT16_MAX / b) ? UINT16_MAX : a * b);
}
/**
* @brief Get the numerical value of a base-36 digit.
* Allowed values are [0-9, A-Z], with letters mapped to values of 10-35.
* Lowercase letters are mapped to the same values as the uppercase ones.
* Any other char is invalid and will be attributed a value of 0.
*
* @param c the char representing a digit in base-36
* @return u32
*/
static inline uint32_t base36_digit_value(char c)
{
switch (c)
{
case '0' ... '9':
return c - '0';
case 'A' ... 'Z':
return 10 + c - 'A';
case 'a' ... 'z':
return 10 + c - 'a';
default:
return 0;
}
}
/**
* @brief Get the char corresponding to a base-36 digit's numerical value.
* Inverse operation of base36_digit_value
*
* @param n decimal value of the base-36 char we want to get
* @return char
*
* @sa base36_digit_value
*/
static inline char base36_digit_char(uint32_t n)
{
switch (n)
{
case 0 ... 9:
return n + '0';
case 10 ... 35:
return n - 10 + 'A';
default:
return '\0';
}
}
/**
* @brief Get 36 to the power `i`
*
* @param i power of 36 we want, between 0 and `BASE36_MAX_DIGITS - 1`
* @return 36 to the power `i`
*
* @sa base36_digit_value
*/
static inline uint32_t get_base36_power(uint8_t i)
{
if (i >= BASE36_MAX_DIGITS)
{
return 0;
}
static const uint32_t powers_of_36[BASE36_MAX_DIGITS] = {1, 36, 1296, 46656, 1679616, 60466176};
return powers_of_36[i];
}
uint32_t base36_to_u32(const char b36_str[])
{
uint32_t res = 0;
for (uint8_t i = 0; i < BASE36_MAX_DIGITS; i++)
{
res += base36_digit_value(b36_str[i]) * get_base36_power(BASE36_MAX_DIGITS - i - 1);
}
return res;
}
void u32_to_base36(const uint32_t n, char b36_str[])
{
uint32_t power;
uint32_t acc = (n > MAX_BASE36) ? MAX_BASE36 : n;
for (int i = 0; i < BASE36_MAX_DIGITS; i++)
{
power = get_base36_power(BASE36_MAX_DIGITS - i - 1);
b36_str[i] = base36_digit_char(acc / power);
acc = acc % power;
}
// Properly end the string
b36_str[BASE36_MAX_DIGITS] = '\0';
}