Coin & Dice Toss & Geomantic Divination Watch Faces (#235)
* init * advanced latlon setting * simple functionality done * lat lon high precision fwd bwd * edit toggle * added readme for branch * DD DMS conversion & cleanup * DD to OLC conversion * olc encoding & decoding * OLC implementation * swapped bools for modes, code cleanup * place name editor * updated button logic, fixed display * load and save places in state array * todo list * simplified OLC functions * geohash conversion functions * geohash display & digit functions * todo * finished geohash implementation * code display function, defaults, bugfixes * read/write file/reg logic * long light in DATA to cancel * write to registry * todo * read & write backup register * file read/write * todo * new more concise button logic, optimizations * todo * renamed & cleaned up, fixed button logic * documentation * documentation * LAP mode for all coordinate screens * faster and more precise geohash algorithm * updated description * updated docu * simple place face * bugfixes, updated documentation * init * meh * added public functions for OLC and Geohash * randonauting face * fix * display fix * cleanup * bugfixes * bugfix * added place * fixed TRNG call * fixed declaration conflict * modulo bias filter * simplified things, chance RNG selection * fixed button logic, better menus * cleanup * documentation * docu fixes * init * basic functions * all needed static functions done * progress * coins and dice done * progress * place update * divination faces functionality done * better divine_bit * figure numbers and names * captions optional * coin animation * dice animation & optimizations * animation * changed names, documented * bugfix * cleanup * reset config --------- Co-authored-by: joeycastillo <joeycastillo@utexas.edu>
This commit is contained in:
		
							parent
							
								
									ccf44281e7
								
							
						
					
					
						commit
						34030bf3e4
					
				| @ -112,6 +112,8 @@ SRCS += \ | |||||||
|   ../watch_faces/complication/invaders_face.c \
 |   ../watch_faces/complication/invaders_face.c \
 | ||||||
|   ../watch_faces/clock/world_clock2_face.c \
 |   ../watch_faces/clock/world_clock2_face.c \
 | ||||||
|   ../watch_faces/complication/time_left_face.c \
 |   ../watch_faces/complication/time_left_face.c \
 | ||||||
|  |   ../watch_faces/complication/toss_up_face.c \
 | ||||||
|  |   ../watch_faces/complication/geomancy_face.c \
 | ||||||
| # New watch faces go above this line.
 | # New watch faces go above this line.
 | ||||||
| 
 | 
 | ||||||
| # Leave this line at the bottom of the file; it has all the targets for making your project.
 | # Leave this line at the bottom of the file; it has all the targets for making your project.
 | ||||||
|  | |||||||
| @ -87,6 +87,8 @@ | |||||||
| #include "invaders_face.h" | #include "invaders_face.h" | ||||||
| #include "world_clock2_face.h" | #include "world_clock2_face.h" | ||||||
| #include "time_left_face.h" | #include "time_left_face.h" | ||||||
|  | #include "toss_up_face.h" | ||||||
|  | #include "geomancy_face.h" | ||||||
| #include "dual_timer_face.h" | #include "dual_timer_face.h" | ||||||
| // New includes go above this line.
 | // New includes go above this line.
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										356
									
								
								movement/watch_faces/complication/geomancy_face.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								movement/watch_faces/complication/geomancy_face.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,356 @@ | |||||||
|  | /*
 | ||||||
|  |  * MIT License | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2023 Tobias Raayoni Last / @randogoth | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include "toss_up_face.h" | ||||||
|  | #include "geomancy_face.h" | ||||||
|  | 
 | ||||||
|  | // CONSTANTS //////////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | // The Bagua 八卦 Trigrams encoded as 3bit tribbles, represented as binary integer
 | ||||||
|  | static const uint32_t bagua = 0b00000101001110010111011100000000; | ||||||
|  | 
 | ||||||
|  | // The King Wen Sequence 文王卦序 of the I Ching 易經 Hexagrams 卦 encoded as an array
 | ||||||
|  | // of decimal integers in the order of two combined Trigram tribbles from 0b000000 to 
 | ||||||
|  | // 0b111111 
 | ||||||
|  | static const uint8_t wen_order[] = { | ||||||
|  |      1, 22,  7, 19, 15, 34, 44, 11,  | ||||||
|  |     14, 51, 38, 52, 61, 55, 30, 32,  | ||||||
|  |      6,  3, 28, 58, 39, 63, 46,  5,  | ||||||
|  |     45, 17, 47, 56, 31, 49, 27, 43,  | ||||||
|  |     23, 26,  2, 41, 50, 20, 16, 24,  | ||||||
|  |     35, 21, 62, 36, 54, 29, 48, 12,  | ||||||
|  |     18, 40, 59, 60, 53, 37, 57,  9,  | ||||||
|  |     10, 25,  4,  8, 33, 13, 42,  0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // The geomantic figures encoded as 4 bit nibbles, represented as hexadecimal integer
 | ||||||
|  | static const uint64_t geomantic = 0x4ABF39D25E76C180; | ||||||
|  | 
 | ||||||
|  | // Abbreviations of the Names of the Geomantic Figures in the order of the 4 bit nibbles
 | ||||||
|  | // from 0b0000 to 0b1111
 | ||||||
|  | static const char figures[16][2] = { | ||||||
|  |     "VI" /* Via */, "Hd" /* Head of the Dragon */, "PA" /* Puella */, "GF" /* Greater Fortune*/,  | ||||||
|  |     "PR" /* Puer */, "AQ" /* Acquisitio */, "CA" /* Carcer */, "TR" /* Tristitia */, | ||||||
|  |     "Td" /* Tail of the Dragon */, "CO" /* Conjunctio */, "AM" /* Amissio */, "AL" /* Albus */, | ||||||
|  |     "LF" /* Lesser Fortune */, "RU" /* Rubeus */, "LA" /* Laetitia */, "PO" /* Populus */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // DECLARATIONS ///////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | static void geomancy_face_display(); | ||||||
|  | static nibble_t _geomancy_pick_figure(); | ||||||
|  | static tribble_t _iching_pick_trigram(); | ||||||
|  | static uint8_t _iching_form_hexagram(); | ||||||
|  | static void _geomancy_display(nibble_t code); | ||||||
|  | static void _display_hexagram(uint8_t hexagram, char* str); | ||||||
|  | static void _fix_broken_line(uint8_t hexagram); | ||||||
|  | static void _throw_animation(geomancy_state_t *state); | ||||||
|  | 
 | ||||||
|  | // WATCH FACE FUNCTIONS ///////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | void geomancy_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) { | ||||||
|  |     (void) settings; | ||||||
|  |     if (*context_ptr == NULL) { | ||||||
|  |         *context_ptr = malloc(sizeof(geomancy_state_t)); | ||||||
|  |         memset(*context_ptr, 0, sizeof(geomancy_state_t)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void geomancy_face_activate(movement_settings_t *settings, void *context) { | ||||||
|  |     (void) settings; | ||||||
|  |     (void) context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool geomancy_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { | ||||||
|  |     geomancy_state_t *state = (geomancy_state_t *)context; | ||||||
|  | 
 | ||||||
|  |     switch (event.event_type) { | ||||||
|  |         case EVENT_ACTIVATE: | ||||||
|  |             state->animate = false; | ||||||
|  |             state->animation = 0; | ||||||
|  |             watch_display_string("    IChing", 0); | ||||||
|  |             break; | ||||||
|  |         case EVENT_TICK: | ||||||
|  |             if ( state->animate ) { | ||||||
|  |                 state->animation = (state->animation + 1) % 39; | ||||||
|  |                 geomancy_face_display(state); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case EVENT_LIGHT_BUTTON_DOWN: | ||||||
|  |             break; | ||||||
|  |         case EVENT_LIGHT_BUTTON_UP: | ||||||
|  |             if ( state->animate ) break; | ||||||
|  |             if ( state->mode <= 1 ) state->mode = 2; | ||||||
|  |             else if ( state->mode >= 2 ) state->mode = 0; | ||||||
|  |             geomancy_face_display(state); | ||||||
|  |             break; | ||||||
|  |         case EVENT_ALARM_BUTTON_UP: | ||||||
|  |             if ( state->animate ) break; | ||||||
|  |             switch ( state->mode ) { | ||||||
|  |                 case 0: | ||||||
|  |                     state->mode++; | ||||||
|  |                 case 1: | ||||||
|  |                     state->animate = true; | ||||||
|  |                     state->i_ching_hexagram = _iching_form_hexagram(); | ||||||
|  |                     break; | ||||||
|  |                 case 2: | ||||||
|  |                     state->mode++; | ||||||
|  |                 case 3: | ||||||
|  |                     state->animate = true; | ||||||
|  |                     state->geomantic_figure = _geomancy_pick_figure().bits; | ||||||
|  |                     break; | ||||||
|  |                 default: | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |             geomancy_face_display(state); | ||||||
|  |             break; | ||||||
|  |         case EVENT_ALARM_LONG_PRESS: | ||||||
|  |             if ( state->animate ) break; | ||||||
|  |             state->caption = !state->caption; | ||||||
|  |             watch_display_string("    ", 0); | ||||||
|  |             geomancy_face_display(state); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             return movement_default_loop_handler(event, settings); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void geomancy_face_resign(movement_settings_t *settings, void *context) { | ||||||
|  |     (void) settings; | ||||||
|  |     (void) context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // STATIC FUNCTIONS ///////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | /** @brief display handler */ | ||||||
|  | static void geomancy_face_display(geomancy_state_t *state) { | ||||||
|  |     char token[7] = {0}; | ||||||
|  |     nibble_t figure = *((nibble_t*) &state->geomantic_figure); | ||||||
|  |     switch ( state->mode ) { | ||||||
|  |         case 0: | ||||||
|  |             watch_display_string("    IChing", 0); | ||||||
|  |             break; | ||||||
|  |         case 1: | ||||||
|  |             _throw_animation(state); | ||||||
|  |             if ( !state->animate ) { | ||||||
|  |                 _display_hexagram(state->i_ching_hexagram, token); | ||||||
|  |                 watch_display_string(token, 4); | ||||||
|  |                 _fix_broken_line(state->i_ching_hexagram); | ||||||
|  |                 if (state->caption) { | ||||||
|  |                     sprintf(token, "%2d", wen_order[state->i_ching_hexagram] + 1); | ||||||
|  |                     watch_display_string(token, 2); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 2: | ||||||
|  |             watch_display_string("    GeomCy", 0); | ||||||
|  |             break; | ||||||
|  |         case 3: | ||||||
|  |             _throw_animation(state); | ||||||
|  |             if ( !state->animate ) { | ||||||
|  |                 if ( state->caption ) { | ||||||
|  |                     sprintf(token, "%c%c", figures[state->geomantic_figure][0], figures[state->geomantic_figure][1]); | ||||||
|  |                     watch_display_string(token, 0); | ||||||
|  |                 } | ||||||
|  |                 _geomancy_display(figure); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief screen clearing animation between castings */ | ||||||
|  | static void _throw_animation(geomancy_state_t *state) { | ||||||
|  |     movement_request_tick_frequency(16); | ||||||
|  |     switch ( state->animation ) { | ||||||
|  |         case 0: | ||||||
|  |             watch_set_pixel(0, 22); | ||||||
|  |             break; | ||||||
|  |         case 1: | ||||||
|  |             watch_set_pixel(2, 22); | ||||||
|  |             watch_set_pixel(2, 23); | ||||||
|  |             watch_clear_pixel(0, 22); | ||||||
|  |             break; | ||||||
|  |         case 2: | ||||||
|  |             watch_set_pixel(1, 22); | ||||||
|  |             watch_set_pixel(0, 23); | ||||||
|  |             break; | ||||||
|  |         case 3: | ||||||
|  |             watch_set_pixel(2, 0); | ||||||
|  |             watch_set_pixel(1, 0); | ||||||
|  |             watch_set_pixel(2, 21); | ||||||
|  |             watch_set_pixel(1, 21); | ||||||
|  |             watch_clear_pixel(2, 22); | ||||||
|  |             watch_clear_pixel(1, 22); | ||||||
|  |             watch_clear_pixel(2, 23); | ||||||
|  |             watch_clear_pixel(0, 23); | ||||||
|  |             watch_clear_pixel(1, 23); | ||||||
|  |             break; | ||||||
|  |         case 4: | ||||||
|  |             watch_set_pixel(1, 17); | ||||||
|  |             watch_set_pixel(0, 20); | ||||||
|  |             watch_set_pixel(2, 10); | ||||||
|  |             watch_set_pixel(0, 1); | ||||||
|  |             break; | ||||||
|  |         case 5: | ||||||
|  |             watch_clear_pixel(2, 21); | ||||||
|  |             watch_clear_pixel(1, 21); | ||||||
|  |             watch_clear_pixel(2, 0); | ||||||
|  |             watch_clear_pixel(1, 0); | ||||||
|  |             watch_clear_pixel(1, 20); | ||||||
|  |             watch_clear_pixel(2, 20); | ||||||
|  |             watch_clear_pixel(0, 21); | ||||||
|  |             watch_clear_pixel(1, 1); | ||||||
|  |             watch_clear_pixel(0, 0); | ||||||
|  |             watch_clear_pixel(2, 1); | ||||||
|  |             watch_set_pixel(2, 19); | ||||||
|  |             watch_set_pixel(0, 19); | ||||||
|  |             watch_set_pixel(1, 2); | ||||||
|  |             watch_set_pixel(0, 2); | ||||||
|  |             break; | ||||||
|  |         case 6: | ||||||
|  |             watch_clear_pixel(1, 17); | ||||||
|  |             watch_clear_pixel(0, 20); | ||||||
|  |             watch_clear_pixel(2, 10); | ||||||
|  |             watch_clear_pixel(0, 1); | ||||||
|  |             watch_set_pixel(2, 18); | ||||||
|  |             watch_set_pixel(0, 18); | ||||||
|  |             watch_set_pixel(2, 3); | ||||||
|  |             watch_set_pixel(0, 4); | ||||||
|  |             break; | ||||||
|  |         case 7: | ||||||
|  |             watch_clear_pixel(2, 19); | ||||||
|  |             watch_clear_pixel(0, 19); | ||||||
|  |             watch_clear_pixel(1, 18); | ||||||
|  |             watch_clear_pixel(1, 19); | ||||||
|  |             watch_clear_pixel(1, 2); | ||||||
|  |             watch_clear_pixel(0, 2); | ||||||
|  |             watch_clear_pixel(1, 3); | ||||||
|  |             watch_clear_pixel(0, 3); | ||||||
|  |             watch_clear_pixel(2, 2); | ||||||
|  |             watch_set_pixel(1, 4); | ||||||
|  |             watch_set_pixel(0, 5); | ||||||
|  |             break; | ||||||
|  |         case 8: | ||||||
|  |             watch_clear_pixel(2, 18); | ||||||
|  |             watch_clear_pixel(0, 18); | ||||||
|  |             watch_clear_pixel(2, 3); | ||||||
|  |             watch_clear_pixel(0, 4); | ||||||
|  |             watch_set_pixel(2, 5); | ||||||
|  |             watch_set_pixel(1, 6); | ||||||
|  |             break; | ||||||
|  |         case 9: | ||||||
|  |             watch_clear_pixel(1, 4); | ||||||
|  |             watch_clear_pixel(0, 5); | ||||||
|  |             watch_clear_pixel(1, 5); | ||||||
|  |             watch_clear_pixel(2, 4); | ||||||
|  |             watch_clear_pixel(0, 6); | ||||||
|  |             break; | ||||||
|  |         case 10: | ||||||
|  |             watch_clear_pixel(2, 5); | ||||||
|  |             watch_clear_pixel(1, 6); | ||||||
|  |             break; | ||||||
|  |         case 11: | ||||||
|  |             state->animate = false; | ||||||
|  |             state->animation = 0; | ||||||
|  |             movement_request_tick_frequency(1); | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // I CHING FUNCTIONS //////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | /** @brief form a trigram from three random bit picks
 | ||||||
|  |  */ | ||||||
|  | static tribble_t _iching_pick_trigram() { | ||||||
|  |     uint8_t index = (divine_bit() << 2) | (divine_bit() << 1) | divine_bit(); | ||||||
|  |     tribble_t trigram = {(bagua >> (3 * index)) & 0b111}; | ||||||
|  |     return trigram; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief form a hexagram from two trigrams
 | ||||||
|  |  */ | ||||||
|  | static uint8_t _iching_form_hexagram() { | ||||||
|  |     tribble_t inner = _iching_pick_trigram(); | ||||||
|  |     tribble_t outer = _iching_pick_trigram(); | ||||||
|  |     uint8_t hexagram = (inner.bits << 3) | outer.bits; | ||||||
|  |     return hexagram; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief display hexagram
 | ||||||
|  |  *  @details | for unbroken lines and Ξ for broken lines, left of display is bottom | ||||||
|  |  */ | ||||||
|  | static void _display_hexagram(uint8_t hexagram, char* str) { | ||||||
|  |     str[6] = '\0';  // Null-terminate the string
 | ||||||
|  |     for (uint8_t i = 0; i < 6; i++) { | ||||||
|  |         if (hexagram & (1 << (5 - i))) { | ||||||
|  |             str[i] = '1'; | ||||||
|  |         } else { | ||||||
|  |             str[i] = '='; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief when Ξ digits show as = then manually add a line on top
 | ||||||
|  |  */ | ||||||
|  | static void _fix_broken_line(uint8_t hexagram) { | ||||||
|  |     for (uint8_t i = 0; i < 6; i++) { | ||||||
|  |         if (!(hexagram & (1 << (5 - i)))) { | ||||||
|  |             if ( i == 1 ) watch_set_pixel(2, 20); | ||||||
|  |             if ( i == 3 ) watch_set_pixel(2, 1); | ||||||
|  |             if ( i == 4 ) watch_set_pixel(2, 2); | ||||||
|  |             if ( i == 5 ) watch_set_pixel(2, 4); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GEOMANCY FUNCTIONS /////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | /** @brief choose a geomantic figure from four random bits
 | ||||||
|  |  *  @details 0 represents · and 1 represents : counting from the bottom | ||||||
|  |  */ | ||||||
|  | static nibble_t _geomancy_pick_figure() { | ||||||
|  |     uint8_t index = (divine_bit() << 3) | (divine_bit() << 2) | (divine_bit() << 1) | divine_bit(); | ||||||
|  |     nibble_t figure = {(geomantic >> (4 * (15 - index))) & 0xF}; | ||||||
|  |     return figure; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief display the geomantic figure, left of display is bottom
 | ||||||
|  |  */ | ||||||
|  | static void _geomancy_display(nibble_t code) { | ||||||
|  |     // draw geomantic figures
 | ||||||
|  |     bool row1 = (code.bits >> 3) & 1; | ||||||
|  |     bool row2 = (code.bits >> 2) & 1; | ||||||
|  |     bool row3 = (code.bits >> 1) & 1; | ||||||
|  |     bool row4 = code.bits & 1; | ||||||
|  | 
 | ||||||
|  |     if ( row1 ) watch_set_pixel(1, 18); else watch_set_pixel(1, 19); | ||||||
|  |     if ( row2 ) { watch_set_pixel(2, 20); watch_set_pixel(0, 21);} else watch_set_pixel(1, 20); | ||||||
|  |     if ( row3 ) watch_set_pixel(0, 22); else watch_set_pixel(1, 23); | ||||||
|  |     if ( row4 ) { watch_set_pixel(2, 1); watch_set_pixel(0, 0);} else watch_set_pixel(1, 1); | ||||||
|  | } | ||||||
							
								
								
									
										99
									
								
								movement/watch_faces/complication/geomancy_face.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								movement/watch_faces/complication/geomancy_face.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | |||||||
|  | /*
 | ||||||
|  |  * MIT License | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2023 Tobias Raayoni Last / @randogoth | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef GEOMANCY_FACE_H_ | ||||||
|  | #define GEOMANCY_FACE_H_ | ||||||
|  | 
 | ||||||
|  | #include "movement.h" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * GEOMANCY WATCH FACE | ||||||
|  |  * | ||||||
|  |  * A simple and straightforward watch face for the ancient Eastern geomantic divination system | ||||||
|  |  * of I Ching and the western system of "Geomancy". It is an optional addition to the Toss Up | ||||||
|  |  * Face. | ||||||
|  |  *  | ||||||
|  |  * The LIGHT button toggles between the two systems of geomancy. | ||||||
|  |  *  | ||||||
|  |  * The ALARM button casts an I Ching hexagram or Geomantic figure based on drawing virtual | ||||||
|  |  * stalks from the True Random Number Generator in the Sensor Watch. | ||||||
|  |  *  | ||||||
|  |  * The figures are flipped 90 degrees clockwise, so the left side is the bottom and the | ||||||
|  |  * right side the top. | ||||||
|  |  *  | ||||||
|  |  * LONG PRESSING ALARM toggles the display of the King Wen sequence index for the cast I Ching | ||||||
|  |  * Hexagram (https://en.wikipedia.org/wiki/King_Wen_sequence )or the abbreviated name for the
 | ||||||
|  |  * cast Geomantic Figure: | ||||||
|  |  *  | ||||||
|  |  * GF - Greater Fortune (Fortuna Major) | ||||||
|  |  * LF - Lesser Fortune (Fortuna Minor) | ||||||
|  |  * PO - Populus | ||||||
|  |  * VI - Via | ||||||
|  |  * AL - Albus | ||||||
|  |  * CO - Conjunctio | ||||||
|  |  * PA - Puella | ||||||
|  |  * AM - Amissio | ||||||
|  |  * PR - Puer | ||||||
|  |  * RU - Rubeus | ||||||
|  |  * AQ - Acquisitio | ||||||
|  |  * LA - Laetitia | ||||||
|  |  * TR - Tristitia | ||||||
|  |  * CA - Carcer | ||||||
|  |  * HD - Head of the Dragon (Caput Draconis) | ||||||
|  |  * TD - Tail of the Dragon (Cauda Draconis) | ||||||
|  |  *  | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t bits : 4; | ||||||
|  | } nibble_t; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t bits : 3; | ||||||
|  | } tribble_t; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t mode : 3; | ||||||
|  |     uint8_t geomantic_figure; | ||||||
|  |     uint8_t i_ching_hexagram : 6; | ||||||
|  |     bool caption; | ||||||
|  |     uint8_t animation; | ||||||
|  |     bool animate; | ||||||
|  | } geomancy_state_t; | ||||||
|  | 
 | ||||||
|  | void geomancy_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr); | ||||||
|  | void geomancy_face_activate(movement_settings_t *settings, void *context); | ||||||
|  | bool geomancy_face_loop(movement_event_t event, movement_settings_t *settings, void *context); | ||||||
|  | void geomancy_face_resign(movement_settings_t *settings, void *context); | ||||||
|  | 
 | ||||||
|  | #define geomancy_face ((const watch_face_t){ \ | ||||||
|  |     geomancy_face_setup, \ | ||||||
|  |     geomancy_face_activate, \ | ||||||
|  |     geomancy_face_loop, \ | ||||||
|  |     geomancy_face_resign, \ | ||||||
|  |     NULL, \ | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | #endif // GEOMANCY_FACE_H_
 | ||||||
|  | 
 | ||||||
							
								
								
									
										790
									
								
								movement/watch_faces/complication/toss_up_face.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										790
									
								
								movement/watch_faces/complication/toss_up_face.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,790 @@ | |||||||
|  | /*
 | ||||||
|  |  * MIT License | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2023 Tobias Raayoni Last / @randogoth | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include "toss_up_face.h" | ||||||
|  | #if __EMSCRIPTEN__ | ||||||
|  | #include <time.h> | ||||||
|  | #else | ||||||
|  | #include "saml22j18a.h" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static const char heads[] = { '8', 'h', '4', 'E', '(' }; | ||||||
|  | static const char tails[] = { '0', '+', 'N', '3', ')' }; | ||||||
|  | static const uint8_t dd[] = {2, 4, 6, 8, 10,12,20,24,30,32,36,48,99};  | ||||||
|  | 
 | ||||||
|  | static void _roll_dice_multiple(char* result, uint8_t* dice, uint8_t num_dice); | ||||||
|  | static void _sort_coins(char* token, uint8_t num_bits, uint8_t bits, char* heads, char* tails); | ||||||
|  | void _display_coins(char* token, bool* bit_array, uint8_t length, toss_up_state_t *state); | ||||||
|  | static void _toss_up_face_display(toss_up_state_t *state); | ||||||
|  | static void _dice_animation(toss_up_state_t *state); | ||||||
|  | static void _coin_animation(toss_up_state_t *state); | ||||||
|  | 
 | ||||||
|  | // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | void toss_up_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) { | ||||||
|  |     (void) settings; | ||||||
|  |     if (*context_ptr == NULL) { | ||||||
|  |         *context_ptr = malloc(sizeof(toss_up_state_t)); | ||||||
|  |         memset(*context_ptr, 0, sizeof(toss_up_state_t)); | ||||||
|  |         toss_up_state_t *state = (toss_up_state_t *)*context_ptr; | ||||||
|  | 
 | ||||||
|  |         // defaults
 | ||||||
|  |         state->coin_num = 1; | ||||||
|  |         state->dice_num = 1; | ||||||
|  |         state->dice_sides[0] = 6; | ||||||
|  |         state->dice_sides[1] = 6; | ||||||
|  |         state->dice_sides[2] = 6; | ||||||
|  |         state->coin_style[0] = '8'; | ||||||
|  |         state->coin_style[1] = '0'; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void toss_up_face_activate(movement_settings_t *settings, void *context) { | ||||||
|  |     (void) settings; | ||||||
|  |     (void) context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool toss_up_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { | ||||||
|  |     toss_up_state_t *state = (toss_up_state_t *)context; | ||||||
|  |     uint8_t i = 0; | ||||||
|  |     switch (event.event_type) { | ||||||
|  |         case EVENT_ACTIVATE: | ||||||
|  |             watch_display_string("    Coins ", 0); | ||||||
|  |             break; | ||||||
|  |         case EVENT_TICK: | ||||||
|  |             if ( state->animate ) { | ||||||
|  |                 state->animation = (state->animation + 1); | ||||||
|  |                 _toss_up_face_display(state); | ||||||
|  |             }  | ||||||
|  |             break; | ||||||
|  |         case EVENT_LIGHT_BUTTON_DOWN: | ||||||
|  |             break; | ||||||
|  |         case EVENT_LIGHT_BUTTON_UP: | ||||||
|  |             if ( state->animate ) break; | ||||||
|  |             // change between coins and dice
 | ||||||
|  |             if ( state->mode <= 1 ) state->mode = 2; | ||||||
|  |             else if ( state->mode >= 2 ) state->mode = 0; | ||||||
|  |             _toss_up_face_display(state); | ||||||
|  |             break; | ||||||
|  |         case EVENT_ALARM_BUTTON_UP: | ||||||
|  |             // toss
 | ||||||
|  |             if ( state->animate ) break; | ||||||
|  |             switch (state->mode) { | ||||||
|  |                 case 0: | ||||||
|  |                     state->mode++; | ||||||
|  |                 case 1: | ||||||
|  |                     state->animate = true; | ||||||
|  |                     for (i = 0; i < state->coin_num; i++) { | ||||||
|  |                         state->coins[i] = divine_bit(); | ||||||
|  |                     }              | ||||||
|  |                     break; | ||||||
|  |                 case 2: | ||||||
|  |                     state->mode++; | ||||||
|  |                 case 3: | ||||||
|  |                     state->animate = true; | ||||||
|  |                     for (i = 0; i < state->dice_num; i++) { | ||||||
|  |                         state->dice[i] = roll_dice(state->dice_sides[i]); | ||||||
|  |                     }   | ||||||
|  |                     break; | ||||||
|  |                 default: | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |             _toss_up_face_display(state); | ||||||
|  |             break; | ||||||
|  |         case EVENT_LIGHT_LONG_PRESS: | ||||||
|  |             if ( state->animate ) break; | ||||||
|  |             state->animate = false; | ||||||
|  |             switch (state->mode) { | ||||||
|  |                 case 0: // change to default coin style
 | ||||||
|  |                     state->coin_style[0] = heads[0]; | ||||||
|  |                     state->coin_style[1] = tails[0]; | ||||||
|  |                     state->coinface = 0; | ||||||
|  |                     break; | ||||||
|  |                 case 1: // change the coin style
 | ||||||
|  |                     state->coinface = (state->coinface + 1) % 5; | ||||||
|  |                     state->coin_style[0] = heads[state->coinface]; | ||||||
|  |                     state->coin_style[1] = tails[state->coinface];          | ||||||
|  |                     break; | ||||||
|  |                 case 2: // change to default dice sides
 | ||||||
|  |                     state->dice_sides[0] = 6; | ||||||
|  |                     state->dice_sides[1] = 6; | ||||||
|  |                     state->dice_sides[2] = 6; | ||||||
|  |                     state->dd = 0; | ||||||
|  |                     break; | ||||||
|  |                 case 3: // change the sides of the dice
 | ||||||
|  |                     state->dd = (state->dd + 1) % 13; | ||||||
|  |                     state->dice_sides[state->dice_num-1] = dd[state->dd]; | ||||||
|  |                     state->dice[state->dice_num-1] = dd[state->dd]; | ||||||
|  |                     break; | ||||||
|  |                 default: | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |             _toss_up_face_display(state); | ||||||
|  |             break; | ||||||
|  |         case EVENT_ALARM_LONG_PRESS: | ||||||
|  |             if ( state->animate ) break; | ||||||
|  |             state->animate = false; | ||||||
|  |             switch (state->mode) { | ||||||
|  |                 case 0: // back to one coin
 | ||||||
|  |                     state->coin_num = 1; | ||||||
|  |                     break; | ||||||
|  |                 case 1: // up to 6 coins total
 | ||||||
|  |                     state->coin_num = (state->coin_num % 6) + 1;              | ||||||
|  |                     break; | ||||||
|  |                 case 2: // back to one dice
 | ||||||
|  |                     state->dice_num = 1; | ||||||
|  |                     break; | ||||||
|  |                 case 3: // add up to 3 dice total
 | ||||||
|  |                     state->dice_num = (state->dice_num % 3) + 1; | ||||||
|  |                     state->dd = 0; | ||||||
|  |                     break; | ||||||
|  |                 default: | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |             _toss_up_face_display(state); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             return movement_default_loop_handler(event, settings); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void toss_up_face_resign(movement_settings_t *settings, void *context) { | ||||||
|  |     (void) settings; | ||||||
|  |     (void) context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // STATIC FUNCTIONS ///////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | /** @brief handles the display 
 | ||||||
|  |  */ | ||||||
|  | static void _toss_up_face_display(toss_up_state_t *state) { | ||||||
|  |     char buf[11] = {0}; | ||||||
|  |     char token[7] = {0}; | ||||||
|  |     switch ( state->mode ) { | ||||||
|  |         case 0: // coins title
 | ||||||
|  |             sprintf(buf, "    Coins "); | ||||||
|  |             break; | ||||||
|  |         case 1: // coins divination
 | ||||||
|  |             _coin_animation(state); | ||||||
|  |             if ( !state->animate ) { | ||||||
|  |                 watch_clear_display(); | ||||||
|  |                 _display_coins(token, state->coins, state->coin_num, state); | ||||||
|  |                 sprintf(buf, "    %s", token); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 2: // dice title
 | ||||||
|  |             sprintf(buf, "    Dice "); | ||||||
|  |             break; | ||||||
|  |         case 3: // dice divination
 | ||||||
|  |             _dice_animation(state); | ||||||
|  |             if ( !state->animate ) { | ||||||
|  |                 _roll_dice_multiple(token, state->dice, state->dice_num + 1); | ||||||
|  |                 sprintf(buf, "    %s", token); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  |     watch_display_string(buf, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief divination method to derive a bit from 32 TRNG bits
 | ||||||
|  |  */ | ||||||
|  | uint8_t divine_bit(void) { | ||||||
|  |     uint32_t stalks; | ||||||
|  |     do { // modulo bias filter
 | ||||||
|  |         stalks = get_true_entropy(); // get 32 TRNG bits as stalks
 | ||||||
|  |     } while (stalks >= INT32_MAX || stalks <= 0); | ||||||
|  | 
 | ||||||
|  |     uint8_t pile1_xor = 0; | ||||||
|  |     uint8_t pile2_xor = 0; | ||||||
|  |     // Divide the stalks into two piles, alternating ends
 | ||||||
|  |     for (uint8_t i = 0; i < 16; i++) { | ||||||
|  |         uint8_t left_bit = (stalks >> (31 - 2*i)) & 1; | ||||||
|  |         uint8_t right_bit = (stalks >> (30 - 2*i)) & 1; | ||||||
|  |         if (i % 2 == 0) { | ||||||
|  |             pile1_xor ^= left_bit; | ||||||
|  |             pile2_xor ^= right_bit; | ||||||
|  |         } else { | ||||||
|  |             pile1_xor ^= right_bit; | ||||||
|  |             pile2_xor ^= left_bit; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // Take the XOR of the pile results
 | ||||||
|  |     uint8_t result_xor = pile1_xor ^ pile2_xor; | ||||||
|  |     // Output 1 if result_xor is 1, 0 otherwise
 | ||||||
|  |     return result_xor; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief get 32 True Random Number bits
 | ||||||
|  |  */ | ||||||
|  | uint32_t get_true_entropy(void) { | ||||||
|  |     #if __EMSCRIPTEN__ | ||||||
|  |     return rand() % INT32_MAX; | ||||||
|  |     #else | ||||||
|  |     hri_mclk_set_APBCMASK_TRNG_bit(MCLK); | ||||||
|  |     hri_trng_set_CTRLA_ENABLE_bit(TRNG); | ||||||
|  | 
 | ||||||
|  |     while (!hri_trng_get_INTFLAG_reg(TRNG, TRNG_INTFLAG_DATARDY)); // Wait for TRNG data to be ready
 | ||||||
|  | 
 | ||||||
|  |     hri_trng_clear_CTRLA_ENABLE_bit(TRNG); | ||||||
|  |     hri_mclk_clear_APBCMASK_TRNG_bit(MCLK); | ||||||
|  |     return hri_trng_read_DATA_reg(TRNG); // Read a single 32-bit word from TRNG and return it
 | ||||||
|  |     #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // COIN FUNCTIONS /////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | /** @brief sort tossed coins into a pile of heads and a pile of tails
 | ||||||
|  |  */ | ||||||
|  | static void _sort_coins(char* token, uint8_t num_bits, uint8_t bits, char* heads, char* tails) { | ||||||
|  |     uint8_t num_ones = 0; | ||||||
|  |     for (uint8_t i = 0; i < num_bits; i++) { | ||||||
|  |         if ((bits >> i) & 1) { | ||||||
|  |             *token++ = *heads; | ||||||
|  |             num_ones++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if ( num_bits < 6 ) { | ||||||
|  |         for (uint8_t i = 0; i < (6 - num_bits); i++) { | ||||||
|  |             *token++ = ' '; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     for (uint8_t i = 0; i < (num_bits - num_ones); i++) { | ||||||
|  | 
 | ||||||
|  |         *token++ = *tails; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief convert bool array of coinflips to integer for sorting
 | ||||||
|  |  */ | ||||||
|  | void _display_coins(char* token, bool* bit_array, uint8_t length, toss_up_state_t *state) { | ||||||
|  |     uint8_t bits = 0; | ||||||
|  |     for (uint8_t i = 0; i < length; i++) { | ||||||
|  |         if (bit_array[i]) { | ||||||
|  |             bits |= (1 << (length - 1 - i)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     _sort_coins(token, length, bits, &state->coin_style[0], &state->coin_style[1]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief coin animation
 | ||||||
|  |  */ | ||||||
|  | static void _coin_animation(toss_up_state_t *state) { | ||||||
|  |     bool heads = false; | ||||||
|  |     bool tails = false; | ||||||
|  |     for (uint8_t i = 0; i < state->coin_num; i++) { | ||||||
|  |         if (state->coins[i] == true) { | ||||||
|  |             heads++; | ||||||
|  |         } else { | ||||||
|  |             tails++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     movement_request_tick_frequency(32); | ||||||
|  |     switch ( state->animation ) { | ||||||
|  |         case 0: | ||||||
|  |             watch_display_string("      ", 4); | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(0, 18); | ||||||
|  |                 watch_set_pixel(2, 18); | ||||||
|  |             } else { | ||||||
|  |                 state->animation = 12; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 1: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(1, 18); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 2: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(0, 19); | ||||||
|  |                 watch_set_pixel(2, 19); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 3: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(0, 18); | ||||||
|  |                 watch_clear_pixel(2, 18); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 4: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(1, 18); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 5: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(0, 19); | ||||||
|  |                 watch_clear_pixel(2, 19); | ||||||
|  |                 watch_set_pixel(1, 17); | ||||||
|  |                 watch_set_pixel(0, 20); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 6: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(2, 20); | ||||||
|  |                 watch_set_pixel(0, 21); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 7: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(1, 21); | ||||||
|  |                 watch_set_pixel(2, 21); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 8: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(1, 17); | ||||||
|  |                 watch_clear_pixel(0, 20); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 9: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(2, 20); | ||||||
|  |                 watch_clear_pixel(0, 21); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 10: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(1, 21); | ||||||
|  |                 watch_clear_pixel(2, 21); | ||||||
|  |                 watch_set_pixel(1, 22); | ||||||
|  |                 watch_set_pixel(2, 22); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 11: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(0, 22); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 12: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(2, 23); | ||||||
|  |                 watch_set_pixel(0, 23); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(0, 18); | ||||||
|  |                 watch_set_pixel(2, 18); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 13: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(1, 22); | ||||||
|  |                 watch_clear_pixel(2, 22); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(1, 18); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 14: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(0, 22); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(0, 19); | ||||||
|  |                 watch_set_pixel(2, 19); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 15: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(2, 23); | ||||||
|  |                 watch_clear_pixel(0, 23); | ||||||
|  |                 watch_set_pixel(2, 0); | ||||||
|  |                 watch_set_pixel(1, 0); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(0, 18); | ||||||
|  |                 watch_clear_pixel(2, 18); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 16: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(2, 1); | ||||||
|  |                 watch_set_pixel(0, 0); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(1, 18); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 17: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(2, 10); | ||||||
|  |                 watch_set_pixel(0, 1); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(0, 19); | ||||||
|  |                 watch_clear_pixel(2, 19); | ||||||
|  |                 watch_set_pixel(1, 17); | ||||||
|  |                 watch_set_pixel(0, 20); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 18: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(2, 0); | ||||||
|  |                 watch_clear_pixel(1, 0); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(2, 20); | ||||||
|  |                 watch_set_pixel(0, 21); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 19: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(2, 1); | ||||||
|  |                 watch_clear_pixel(0, 0); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(1, 21); | ||||||
|  |                 watch_set_pixel(2, 21); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 20: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(2, 1); | ||||||
|  |                 watch_set_pixel(0, 0); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(1, 17); | ||||||
|  |                 watch_clear_pixel(0, 20); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 21: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(2, 0); | ||||||
|  |                 watch_set_pixel(1, 0); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(2, 20); | ||||||
|  |                 watch_clear_pixel(0, 21); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 22: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(2, 10); | ||||||
|  |                 watch_clear_pixel(0, 1); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(1, 21); | ||||||
|  |                 watch_clear_pixel(2, 21); | ||||||
|  |                 watch_set_pixel(1, 22); | ||||||
|  |                 watch_set_pixel(2, 22); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 23: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(2, 1); | ||||||
|  |                 watch_clear_pixel(0, 0); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(0, 22); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 24: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(2, 23); | ||||||
|  |                 watch_set_pixel(0, 23); | ||||||
|  |                 watch_clear_pixel(2, 0); | ||||||
|  |                 watch_clear_pixel(1, 0); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(2, 23); | ||||||
|  |                 watch_set_pixel(0, 23); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 25: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(0, 22); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(1, 22); | ||||||
|  |                 watch_clear_pixel(2, 22); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 26: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(1, 22); | ||||||
|  |                 watch_set_pixel(2, 22); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(0, 22); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 27: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(2, 23); | ||||||
|  |                 watch_clear_pixel(0, 23); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(2, 23); | ||||||
|  |                 watch_clear_pixel(0, 23); | ||||||
|  |                 watch_set_pixel(2, 0); | ||||||
|  |                 watch_set_pixel(1, 0); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 28: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(0, 22); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(2, 1); | ||||||
|  |                 watch_set_pixel(0, 0); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 29: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(1, 21); | ||||||
|  |                 watch_set_pixel(2, 21); | ||||||
|  |                 watch_clear_pixel(1, 22); | ||||||
|  |                 watch_clear_pixel(2, 22); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(2, 10); | ||||||
|  |                 watch_set_pixel(0, 1); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 30: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(2, 20); | ||||||
|  |                 watch_set_pixel(0, 21); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(1, 0); | ||||||
|  |                 watch_clear_pixel(2, 0); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 31: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(1, 17); | ||||||
|  |                 watch_set_pixel(0, 20); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(2, 1); | ||||||
|  |                 watch_clear_pixel(0, 0); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 32: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(1, 21); | ||||||
|  |                 watch_clear_pixel(2, 21); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(2, 10); | ||||||
|  |                 watch_clear_pixel(0, 1); | ||||||
|  |                 watch_set_pixel(0, 2); | ||||||
|  |                 watch_set_pixel(1, 2); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 33: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(2, 20); | ||||||
|  |                 watch_clear_pixel(0, 21); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(2, 2); | ||||||
|  |                 watch_set_pixel(0, 3); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 34: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(0, 19); | ||||||
|  |                 watch_set_pixel(2, 19); | ||||||
|  |                 watch_clear_pixel(1, 17); | ||||||
|  |                 watch_clear_pixel(0, 20); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(2, 3); | ||||||
|  |                 watch_set_pixel(0, 4); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 35: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(1, 18); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(1, 2); | ||||||
|  |                 watch_clear_pixel(0, 2); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 36: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_set_pixel(0, 18); | ||||||
|  |                 watch_set_pixel(2, 18); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(2, 2); | ||||||
|  |                 watch_clear_pixel(0, 3); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 37: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(0, 19); | ||||||
|  |                 watch_clear_pixel(2, 19); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_clear_pixel(2, 3); | ||||||
|  |                 watch_clear_pixel(0, 4); | ||||||
|  |                 watch_set_pixel(1, 4); | ||||||
|  |                 watch_set_pixel(0, 5); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 38: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(1, 18); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(2, 4); | ||||||
|  |                 watch_set_pixel(0, 6); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case 39: | ||||||
|  |             if ( heads ) { | ||||||
|  |                 watch_clear_pixel(0, 18); | ||||||
|  |                 watch_clear_pixel(2, 18); | ||||||
|  |             } | ||||||
|  |             if ( tails ) { | ||||||
|  |                 watch_set_pixel(1, 6); | ||||||
|  |                 watch_set_pixel(2, 5); | ||||||
|  |             } | ||||||
|  |             state->animate = false; | ||||||
|  |             state->animation = 0; | ||||||
|  |             movement_request_tick_frequency(1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DICE FUNCTIONS /////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | /** @brief rolls a dice
 | ||||||
|  |  */ | ||||||
|  | uint8_t roll_dice(uint8_t sides) { | ||||||
|  |     uint8_t bits_needed = 0; | ||||||
|  |     uint8_t temp_sides = sides - 1; | ||||||
|  |     uint8_t result = 0; | ||||||
|  |     while (temp_sides > 0) { | ||||||
|  |         bits_needed++; // how many bits do we need to represent this number?
 | ||||||
|  |         temp_sides >>= 1; // Shift right to check the next bit
 | ||||||
|  |     } | ||||||
|  |     do { | ||||||
|  |         result = 0; | ||||||
|  |         for (int i = 0; i < bits_needed; i++) { | ||||||
|  |             result <<= 1; // Shift left to make room for the next bit
 | ||||||
|  |             result |= divine_bit(); // Add the next bit to the result
 | ||||||
|  |         } | ||||||
|  |     } while ( result > sides -1 ); | ||||||
|  |     return result + 1; // Add 1 to convert the range from 0 to sides-1 to 1 to sides
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief roll multiple dice and print a char array for displaying them
 | ||||||
|  |  */ | ||||||
|  | static void _roll_dice_multiple(char* result, uint8_t* dice, uint8_t num_dice) { | ||||||
|  |     // initialize the result array to all spaces
 | ||||||
|  |     memset(result, ' ', 6); | ||||||
|  | 
 | ||||||
|  |     // roll the dice and write the result to the result array
 | ||||||
|  |     for (uint8_t i = 0; i < num_dice-1; i++) { | ||||||
|  |         uint8_t dice_result = dice[i]; | ||||||
|  |         uint8_t tens_digit = dice_result / 10; | ||||||
|  |         uint8_t ones_digit = dice_result % 10; | ||||||
|  |         result[(i * 2)] = tens_digit == 0 ? ' ' : (char)('0' + tens_digit); | ||||||
|  |         result[(i * 2) + 1] = (char)('0' + ones_digit); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** @brief dice animation
 | ||||||
|  |  */ | ||||||
|  | static void _dice_animation(toss_up_state_t *state) { | ||||||
|  |     watch_display_string("      ", 4); | ||||||
|  |     for (uint8_t i = 0; i < state->dice_num; i++) { | ||||||
|  |         watch_display_string("0",i*2 + 5); | ||||||
|  |     } | ||||||
|  |     movement_request_tick_frequency(16); | ||||||
|  |     switch ( state->animation ) { | ||||||
|  |         case 0: | ||||||
|  |             watch_clear_pixel(1, 17); | ||||||
|  |             watch_clear_pixel(0, 0); | ||||||
|  |             watch_clear_pixel(1, 6); | ||||||
|  |             break; | ||||||
|  |         case 1: | ||||||
|  |             watch_clear_pixel(2, 20); | ||||||
|  |             watch_clear_pixel(1, 0); | ||||||
|  |             watch_clear_pixel(0, 6); | ||||||
|  |             break; | ||||||
|  |         case 2: | ||||||
|  |             watch_clear_pixel(2, 21); | ||||||
|  |             watch_clear_pixel(2, 0); | ||||||
|  |             watch_clear_pixel(0, 5); | ||||||
|  |             break; | ||||||
|  |         case 3: | ||||||
|  |             watch_clear_pixel(1, 21); | ||||||
|  |             watch_clear_pixel(2, 1); | ||||||
|  |             watch_clear_pixel(1, 4); | ||||||
|  |             break; | ||||||
|  |         case 4: | ||||||
|  |             watch_clear_pixel(0, 21); | ||||||
|  |             watch_clear_pixel(2, 10); | ||||||
|  |             watch_clear_pixel(2, 4); | ||||||
|  |             break; | ||||||
|  |         case 5: | ||||||
|  |             watch_clear_pixel(0, 20); | ||||||
|  |             watch_clear_pixel(0, 1); | ||||||
|  |             watch_clear_pixel(2, 5); | ||||||
|  |             break; | ||||||
|  |         case 6: | ||||||
|  |             watch_clear_pixel(1, 17); | ||||||
|  |             watch_clear_pixel(0, 0); | ||||||
|  |             watch_clear_pixel(1, 6); | ||||||
|  |             break; | ||||||
|  |         case 7: | ||||||
|  |             watch_clear_pixel(2, 20); | ||||||
|  |             watch_clear_pixel(1, 0); | ||||||
|  |             watch_clear_pixel(0, 6); | ||||||
|  |             break; | ||||||
|  |         case 8: | ||||||
|  |             watch_clear_pixel(2, 21); | ||||||
|  |             watch_clear_pixel(2, 0); | ||||||
|  |             watch_clear_pixel(0, 5); | ||||||
|  |             break; | ||||||
|  |         case 9: | ||||||
|  |             watch_clear_pixel(1, 21); | ||||||
|  |             watch_clear_pixel(2, 1); | ||||||
|  |             watch_clear_pixel(1, 4); | ||||||
|  |             break; | ||||||
|  |         case 10: | ||||||
|  |             watch_clear_pixel(0, 21); | ||||||
|  |             watch_clear_pixel(2, 10); | ||||||
|  |             watch_clear_pixel(2, 4); | ||||||
|  |             break; | ||||||
|  |         case 11: | ||||||
|  |             watch_clear_pixel(0, 20); | ||||||
|  |             watch_clear_pixel(0, 1); | ||||||
|  |             watch_clear_pixel(2, 5); | ||||||
|  |             state->animate = false; | ||||||
|  |             state->animation = 0; | ||||||
|  |             movement_request_tick_frequency(1); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										112
									
								
								movement/watch_faces/complication/toss_up_face.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								movement/watch_faces/complication/toss_up_face.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | |||||||
|  | /*
 | ||||||
|  |  * MIT License | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2023 Tobias Raayoni Last / @randogoth | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef TOSS_UP_FACE_H_ | ||||||
|  | #define TOSS_UP_FACE_H_ | ||||||
|  | 
 | ||||||
|  | #include "movement.h" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * TOSS UP FACE | ||||||
|  |  * ============ | ||||||
|  |  * | ||||||
|  |  * Playful watch face for games of chance or divination using coins or dice. | ||||||
|  |  *  | ||||||
|  |  * LIGHT switches between Coins and Dice mode | ||||||
|  |  *  | ||||||
|  |  * COINS | ||||||
|  |  * ===== | ||||||
|  |  *  | ||||||
|  |  * ALARM tosses a coin. If it lands on heads it gets sorted to the left side of the | ||||||
|  |  * display, if it lands on tails then sorted to the right side. | ||||||
|  |  *  | ||||||
|  |  * LONG PRESSING ALARM adds up to 5 more coins to the toss for more nuance in the decision | ||||||
|  |  * making (e.g. three heads vs two tails could be read as "yes, but with serious doubts"). | ||||||
|  |  *  | ||||||
|  |  * LONG PRESSING LIGHT flips through additional style for the coins from the default Ө/O  | ||||||
|  |  * to H/T (heads/tails), Y/N (yes/no), E/Ǝ, C/Ↄ | ||||||
|  |  *  | ||||||
|  |  * LONG PRESSING ALARM on the "Coins" title page resets to one coin. | ||||||
|  |  * LONG PRESSING LIGHT on the "Coins" title page resets the style to Ө/O | ||||||
|  |  *  | ||||||
|  |  * DICE | ||||||
|  |  * ==== | ||||||
|  |  *  | ||||||
|  |  * ALARM rolls a six sided dice. | ||||||
|  |  *  | ||||||
|  |  * LONG PRESSING ALARM adds up to 2 more dice to the roll. | ||||||
|  |  *  | ||||||
|  |  * LONG PRESSING LIGHT flips through other available polyhedral dice types with less or more | ||||||
|  |  * than the default 6 sides. The options are D2, D4, D6, D8, D10, D12, D20, D24, D30, D32, D36,  | ||||||
|  |  * D48, and a hypothetical D99.  | ||||||
|  |  *  | ||||||
|  |  * When more than one dice is used for a roll this changes only the last added dice. (see Note | ||||||
|  |  * below) | ||||||
|  |  * | ||||||
|  |  * LONG PRESSING ALARM on the "Dice" title page resets to one dice. | ||||||
|  |  * LONG PRESSING LIGHT on the "Dice" title page resets the dice to D6. | ||||||
|  |  *  | ||||||
|  |  * Please Note: If you need let's say a D8, D12, and D20 for your rolls then the procedure to | ||||||
|  |  * set this up would be as follows: from the default screen where you can roll the one D6 dice  | ||||||
|  |  * you would LONG PRESS LIGHT a few times to change the D6 to a D8, then LONG PRESS ALARM to add  | ||||||
|  |  * a second dice, LONG PRESS LIGHT again until the second dice changes to D12, then LONG PRESS | ||||||
|  |  * ALARM to add the third dice and LONG PRESS LIGHT again a few times until it becomes a D20. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     // Anything you need to keep track of, put it here!
 | ||||||
|  |     uint32_t entropy; | ||||||
|  |     uint8_t mode : 4; // 1 coin, 2 coins, 3 coins, 4 coins, dice, iching, geomnc
 | ||||||
|  |     bool setup; | ||||||
|  |     bool coins[6]; | ||||||
|  |     uint8_t coin_num : 3; | ||||||
|  |     char coin_style[2]; | ||||||
|  |     uint8_t coinface : 3; | ||||||
|  |     uint8_t dice[3]; | ||||||
|  |     uint8_t dice_num : 2; | ||||||
|  |     uint8_t dd : 6; | ||||||
|  |     uint8_t dice_sides[3]; | ||||||
|  |     uint8_t animation; | ||||||
|  |     bool animate; | ||||||
|  | } toss_up_state_t; | ||||||
|  | 
 | ||||||
|  | uint32_t get_true_entropy(void); | ||||||
|  | uint8_t divine_bit(void); | ||||||
|  | uint8_t roll_dice(uint8_t sides); | ||||||
|  | void toss_up_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr); | ||||||
|  | void toss_up_face_activate(movement_settings_t *settings, void *context); | ||||||
|  | bool toss_up_face_loop(movement_event_t event, movement_settings_t *settings, void *context); | ||||||
|  | void toss_up_face_resign(movement_settings_t *settings, void *context); | ||||||
|  | 
 | ||||||
|  | #define toss_up_face ((const watch_face_t){ \ | ||||||
|  |     toss_up_face_setup, \ | ||||||
|  |     toss_up_face_activate, \ | ||||||
|  |     toss_up_face_loop, \ | ||||||
|  |     toss_up_face_resign, \ | ||||||
|  |     NULL, \ | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | #endif // TOSS_UP_FACE_H_
 | ||||||
|  | 
 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user