RPS - Allow configuring social info.
This commit is contained in:
parent
c88d5dbf3a
commit
7d87a22b10
@ -21,10 +21,11 @@ Completed work:
|
|||||||
- Log game results & contact info onto SD card.
|
- Log game results & contact info onto SD card.
|
||||||
- Allow viewing past games/scores.
|
- Allow viewing past games/scores.
|
||||||
- A join ACK removes it from the list of available games.
|
- A join ACK removes it from the list of available games.
|
||||||
|
- Config - Allow changing hard-coded CONTACT_INFO message.
|
||||||
|
|
||||||
Remaining work (for subghz version):
|
Remaining work (for subghz version):
|
||||||
|
|
||||||
- Config - Allow changing hard-coded CONTACT_INFO message.
|
- Config - Allow saving CONTACT_INFO message.
|
||||||
- Refactor the code, so it has less duplication.
|
- Refactor the code, so it has less duplication.
|
||||||
- Write tutorial.
|
- Write tutorial.
|
||||||
- Add game ending animations.
|
- Add game ending animations.
|
||||||
@ -59,11 +60,13 @@ These directions assume you are starting at the flipper desktop. If not, please
|
|||||||
- Do the same steps on your second Flipper.
|
- Do the same steps on your second Flipper.
|
||||||
|
|
||||||
- On Flipper 1, choose "Host game".
|
- On Flipper 1, choose "Host game".
|
||||||
|
|
||||||
- select a valid frequency. (like "433.92" in US region)
|
- select a valid frequency. (like "433.92" in US region)
|
||||||
- choose a game number.
|
- choose a game number.
|
||||||
- click OK button to start game.
|
- click OK button to start game.
|
||||||
|
|
||||||
- On Flipper 2, choose "Join game".
|
- On Flipper 2, choose "Join game".
|
||||||
|
|
||||||
- select the same valid frequency as Flipper 1.
|
- select the same valid frequency as Flipper 1.
|
||||||
- "game none" should change to show the game number from Flipper 1 & its name.
|
- "game none" should change to show the game number from Flipper 1 & its name.
|
||||||
-click OK button to join game.
|
-click OK button to join game.
|
||||||
@ -120,7 +123,6 @@ sudo hackrf_transfer -r flipper-chat.rf -f 433920000 -s 8000000 -x 47
|
|||||||
- rock_paper_scissors.c
|
- rock_paper_scissors.c
|
||||||
- This is the game applcation.
|
- This is the game applcation.
|
||||||
|
|
||||||
|
|
||||||
## Example data
|
## Example data
|
||||||
|
|
||||||
- Beacon for game 042:
|
- Beacon for game 042:
|
||||||
@ -147,4 +149,6 @@ RPS:MA042P:Lumyphut
|
|||||||
- Scissors for game 042:
|
- Scissors for game 042:
|
||||||
RPS:MA042S:Lumyphut
|
RPS:MA042S:Lumyphut
|
||||||
|
|
||||||
|
RPS:AA042NYourNameHere :Lumyphut
|
||||||
|
123456789 0123456789 = 19bytes.
|
||||||
|
60-19 = 41 bytes is max length of name.
|
||||||
|
@ -632,7 +632,7 @@ static void rps_render_main_menu(Canvas* canvas, void* ctx) {
|
|||||||
canvas_draw_str_aligned(canvas, 30, 15, AlignLeft, AlignTop, "Host game");
|
canvas_draw_str_aligned(canvas, 30, 15, AlignLeft, AlignTop, "Host game");
|
||||||
canvas_draw_str_aligned(canvas, 30, 27, AlignLeft, AlignTop, "Join game");
|
canvas_draw_str_aligned(canvas, 30, 27, AlignLeft, AlignTop, "Join game");
|
||||||
canvas_draw_str_aligned(canvas, 30, 39, AlignLeft, AlignTop, "Past games");
|
canvas_draw_str_aligned(canvas, 30, 39, AlignLeft, AlignTop, "Past games");
|
||||||
canvas_draw_str_aligned(canvas, 30, 51, AlignLeft, AlignTop, "Edit Message");
|
canvas_draw_str_aligned(canvas, 30, 51, AlignLeft, AlignTop, "Edit contact info");
|
||||||
|
|
||||||
if(game_context->data->local_player == StateMainMenuHost) {
|
if(game_context->data->local_player == StateMainMenuHost) {
|
||||||
canvas_draw_str_aligned(canvas, 20, 15, AlignLeft, AlignTop, ">");
|
canvas_draw_str_aligned(canvas, 20, 15, AlignLeft, AlignTop, ">");
|
||||||
@ -691,6 +691,107 @@ static void rps_render_past_games(Canvas* canvas, void* ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rps_render_choose_social(Canvas* canvas, void* ctx) {
|
||||||
|
GameContext* game_context = ctx;
|
||||||
|
UNUSED(game_context);
|
||||||
|
|
||||||
|
int line = game_context->data->social_line;
|
||||||
|
int index = line - 2;
|
||||||
|
if(index < 0) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_clear(canvas);
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
canvas_draw_str_aligned(canvas, 2, 0, AlignLeft, AlignTop, "Share your...");
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
canvas_draw_str_aligned(canvas, 15, 15, AlignLeft, AlignTop, contact_list[index++] + 1);
|
||||||
|
canvas_draw_str_aligned(canvas, 15, 27, AlignLeft, AlignTop, contact_list[index++] + 1);
|
||||||
|
canvas_draw_str_aligned(canvas, 15, 39, AlignLeft, AlignTop, contact_list[index++] + 1);
|
||||||
|
if(index < (int)COUNT_OF(contact_list)) {
|
||||||
|
canvas_draw_str_aligned(canvas, 15, 51, AlignLeft, AlignTop, contact_list[index++] + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line == 0) {
|
||||||
|
canvas_draw_str_aligned(canvas, 5, 15, AlignLeft, AlignTop, ">");
|
||||||
|
} else if(line == 1) {
|
||||||
|
canvas_draw_str_aligned(canvas, 5, 27, AlignLeft, AlignTop, ">");
|
||||||
|
} else {
|
||||||
|
canvas_draw_str_aligned(canvas, 5, 39, AlignLeft, AlignTop, ">");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char keyboard[4][14] = {
|
||||||
|
{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '.', '_', 8},
|
||||||
|
{'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '!', '$', '*', '&'},
|
||||||
|
{'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '=', '+', ':', '(', ')'},
|
||||||
|
{'Z', 'X', 'C', 'V', 'B', 'N', 'M', ' ', '@', '"', '#', '/', '\'', 13}};
|
||||||
|
|
||||||
|
static char get_char(GameContext* game_context, bool long_press) {
|
||||||
|
int c_r = game_context->data->keyboard_row;
|
||||||
|
int c_c = game_context->data->keyboard_col;
|
||||||
|
char ch = keyboard[c_r][c_c];
|
||||||
|
|
||||||
|
if(!long_press && ch >= 'A' && ch <= 'Z') {
|
||||||
|
ch += 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_arrow(Canvas* canvas, int x, int y, bool tail) {
|
||||||
|
canvas_draw_line(canvas, x, y + 2, x + 4, y + 2);
|
||||||
|
canvas_draw_line(canvas, x, y + 2, x + 2, y);
|
||||||
|
canvas_draw_line(canvas, x, y + 2, x + 2, y + 4);
|
||||||
|
if(tail) {
|
||||||
|
canvas_draw_line(canvas, x + 4, y + 2, x + 4, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rps_render_input_text(Canvas* canvas, void* ctx) {
|
||||||
|
GameContext* game_context = ctx;
|
||||||
|
UNUSED(game_context);
|
||||||
|
|
||||||
|
canvas_clear(canvas);
|
||||||
|
canvas_set_font(canvas, FontKeyboard);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
canvas_draw_str(canvas, 0, 8, furi_string_get_cstr(game_context->data->keyboard_heading));
|
||||||
|
|
||||||
|
canvas_draw_rframe(canvas, 0, 10, 127, 14, 1);
|
||||||
|
int input_offset = furi_string_utf8_length(game_context->data->keyboard_data) - 20;
|
||||||
|
if(input_offset < 0) {
|
||||||
|
input_offset = 0;
|
||||||
|
}
|
||||||
|
canvas_draw_str(
|
||||||
|
canvas, 2, 20, furi_string_get_cstr(game_context->data->keyboard_data) + input_offset);
|
||||||
|
|
||||||
|
int c_r = game_context->data->keyboard_row;
|
||||||
|
int c_c = game_context->data->keyboard_col;
|
||||||
|
|
||||||
|
for(int row = 0; row < 4; row++) {
|
||||||
|
for(int col = 0; col < 14; col++) {
|
||||||
|
char ch = keyboard[row][col];
|
||||||
|
int x = col * 9 + 2;
|
||||||
|
int y = row * 10 + 33;
|
||||||
|
|
||||||
|
if(row == c_r && col == c_c) {
|
||||||
|
canvas_draw_box(canvas, x - 1, y - 8, 7, 9);
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_draw_glyph(canvas, x, y, ch);
|
||||||
|
|
||||||
|
if(ch == 8) {
|
||||||
|
draw_arrow(canvas, x, y - 5, false);
|
||||||
|
} else if(ch == 13) {
|
||||||
|
draw_arrow(canvas, x, y - 5, true);
|
||||||
|
}
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We register this callback to get invoked whenever we need to render the screen.
|
// We register this callback to get invoked whenever we need to render the screen.
|
||||||
// We render the UI on this callback thread.
|
// We render the UI on this callback thread.
|
||||||
// @param canvas rendering surface of the Flipper Zero.
|
// @param canvas rendering surface of the Flipper Zero.
|
||||||
@ -711,6 +812,10 @@ static void rps_render_callback(Canvas* canvas, void* ctx) {
|
|||||||
rps_render_main_menu(canvas, game_context);
|
rps_render_main_menu(canvas, game_context);
|
||||||
} else if(game_context->data->screen_state == ScreenPastGames) {
|
} else if(game_context->data->screen_state == ScreenPastGames) {
|
||||||
rps_render_past_games(canvas, game_context);
|
rps_render_past_games(canvas, game_context);
|
||||||
|
} else if(game_context->data->screen_state == ScreenEditMessage) {
|
||||||
|
rps_render_input_text(canvas, game_context);
|
||||||
|
} else if(game_context->data->screen_state == ScreenChooseSocial) {
|
||||||
|
rps_render_choose_social(canvas, game_context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1522,8 +1627,6 @@ static void load_player_stats(GameContext* game_context) {
|
|||||||
int32_t rock_paper_scissors_app(void* p) {
|
int32_t rock_paper_scissors_app(void* p) {
|
||||||
UNUSED(p);
|
UNUSED(p);
|
||||||
|
|
||||||
UNUSED(contact_list);
|
|
||||||
|
|
||||||
// Configure our initial data.
|
// Configure our initial data.
|
||||||
GameContext* game_context = malloc(sizeof(GameContext));
|
GameContext* game_context = malloc(sizeof(GameContext));
|
||||||
game_context->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
game_context->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||||
@ -1539,6 +1642,8 @@ int32_t rock_paper_scissors_app(void* p) {
|
|||||||
game_context->data->remote_games = NULL;
|
game_context->data->remote_games = NULL;
|
||||||
game_context->data->local_contact = furi_string_alloc();
|
game_context->data->local_contact = furi_string_alloc();
|
||||||
furi_string_set(game_context->data->local_contact, CONTACT_INFO);
|
furi_string_set(game_context->data->local_contact, CONTACT_INFO);
|
||||||
|
game_context->data->keyboard_heading = furi_string_alloc();
|
||||||
|
game_context->data->keyboard_data = furi_string_alloc();
|
||||||
|
|
||||||
load_player_stats(game_context);
|
load_player_stats(game_context);
|
||||||
|
|
||||||
@ -1777,6 +1882,137 @@ int32_t rock_paper_scissors_app(void* p) {
|
|||||||
FURI_LOG_T(TAG, "No support for key %d", event.input.key);
|
FURI_LOG_T(TAG, "No support for key %d", event.input.key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if(
|
||||||
|
game_context->data->screen_state == ScreenEditMessage &&
|
||||||
|
event.input.type == InputTypeShort) {
|
||||||
|
char ch;
|
||||||
|
switch(event.input.key) {
|
||||||
|
case InputKeyLeft:
|
||||||
|
if(game_context->data->keyboard_col) {
|
||||||
|
game_context->data->keyboard_col--;
|
||||||
|
} else {
|
||||||
|
game_context->data->keyboard_col = 13;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputKeyRight:
|
||||||
|
if(game_context->data->keyboard_col < 13) {
|
||||||
|
game_context->data->keyboard_col++;
|
||||||
|
} else {
|
||||||
|
game_context->data->keyboard_col = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputKeyUp:
|
||||||
|
if(game_context->data->keyboard_row) {
|
||||||
|
game_context->data->keyboard_row--;
|
||||||
|
} else {
|
||||||
|
game_context->data->keyboard_row = 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputKeyDown:
|
||||||
|
if(game_context->data->keyboard_row < 3) {
|
||||||
|
game_context->data->keyboard_row++;
|
||||||
|
} else {
|
||||||
|
game_context->data->keyboard_row = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputKeyOk:
|
||||||
|
ch = get_char(game_context, true);
|
||||||
|
if(ch >= ' ') {
|
||||||
|
int len = furi_string_utf8_length(game_context->data->keyboard_data);
|
||||||
|
if(len < KEYBOARD_MAX_LEN) {
|
||||||
|
furi_string_push_back(game_context->data->keyboard_data, ch);
|
||||||
|
} else {
|
||||||
|
single_vibro();
|
||||||
|
}
|
||||||
|
} else if(ch == 8) {
|
||||||
|
int len = furi_string_utf8_length(game_context->data->keyboard_data);
|
||||||
|
if(len > 0) {
|
||||||
|
furi_string_left(game_context->data->keyboard_data, len - 1);
|
||||||
|
}
|
||||||
|
} else if(ch == 13) {
|
||||||
|
furi_string_printf(
|
||||||
|
game_context->data->local_contact,
|
||||||
|
"%c%s",
|
||||||
|
contact_list[game_context->data->social_line][0],
|
||||||
|
furi_string_get_cstr(game_context->data->keyboard_data));
|
||||||
|
FURI_LOG_I(
|
||||||
|
TAG,
|
||||||
|
"Changed contact info to '%s'",
|
||||||
|
furi_string_get_cstr(game_context->data->local_contact));
|
||||||
|
game_context->data->screen_state = ScreenMainMenu;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(
|
||||||
|
game_context->data->screen_state == ScreenEditMessage &&
|
||||||
|
event.input.type == InputTypeLong) {
|
||||||
|
char ch;
|
||||||
|
switch(event.input.key) {
|
||||||
|
case InputKeyOk:
|
||||||
|
ch = get_char(game_context, false);
|
||||||
|
if(ch >= ' ') {
|
||||||
|
int len = furi_string_utf8_length(game_context->data->keyboard_data);
|
||||||
|
if(len < KEYBOARD_MAX_LEN) {
|
||||||
|
furi_string_push_back(game_context->data->keyboard_data, ch);
|
||||||
|
} else {
|
||||||
|
single_vibro();
|
||||||
|
}
|
||||||
|
} else if(ch == 8) {
|
||||||
|
furi_string_left(game_context->data->keyboard_data, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(
|
||||||
|
game_context->data->screen_state == ScreenChooseSocial &&
|
||||||
|
event.input.type == InputTypeShort) {
|
||||||
|
switch(event.input.key) {
|
||||||
|
case InputKeyUp:
|
||||||
|
if(game_context->data->social_line) {
|
||||||
|
game_context->data->social_line--;
|
||||||
|
} else {
|
||||||
|
single_vibro();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputKeyDown:
|
||||||
|
if(++game_context->data->social_line >= (int)COUNT_OF(contact_list)) {
|
||||||
|
game_context->data->social_line--;
|
||||||
|
single_vibro();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputKeyOk:
|
||||||
|
if(game_context->data->social_line == 0) {
|
||||||
|
furi_string_set(game_context->data->local_contact, CONTACT_INFO_NONE);
|
||||||
|
FURI_LOG_I(
|
||||||
|
TAG,
|
||||||
|
"Changed contact info to '%s'",
|
||||||
|
furi_string_get_cstr(game_context->data->local_contact));
|
||||||
|
game_context->data->screen_state = ScreenMainMenu;
|
||||||
|
} else {
|
||||||
|
furi_string_set(
|
||||||
|
game_context->data->keyboard_heading,
|
||||||
|
contact_list[game_context->data->social_line] + 1);
|
||||||
|
game_context->data->keyboard_row = 0;
|
||||||
|
game_context->data->keyboard_col = 13;
|
||||||
|
game_context->data->screen_state = ScreenEditMessage;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else if(
|
} else if(
|
||||||
game_context->data->screen_state == ScreenMainMenu &&
|
game_context->data->screen_state == ScreenMainMenu &&
|
||||||
event.input.type == InputTypeShort) {
|
event.input.type == InputTypeShort) {
|
||||||
@ -1829,7 +2065,7 @@ int32_t rock_paper_scissors_app(void* p) {
|
|||||||
game_context->data->player_stats;
|
game_context->data->player_stats;
|
||||||
game_context->data->screen_state = ScreenPastGames;
|
game_context->data->screen_state = ScreenPastGames;
|
||||||
} else if(game_context->data->local_player == StateMainMenuMessage) {
|
} else if(game_context->data->local_player == StateMainMenuMessage) {
|
||||||
game_context->data->screen_state = ScreenEditMessage;
|
game_context->data->screen_state = ScreenChooseSocial;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -26,12 +26,15 @@
|
|||||||
#define TAG "rock_paper_scissors_app"
|
#define TAG "rock_paper_scissors_app"
|
||||||
|
|
||||||
// Name for "N", followed by your name without any spaces.
|
// Name for "N", followed by your name without any spaces.
|
||||||
#define CONTACT_INFO "NYourNameHere"
|
#define CONTACT_INFO "_"
|
||||||
#define CONTACT_INFO_NONE "E"
|
#define CONTACT_INFO_NONE "_"
|
||||||
|
|
||||||
// The message max length should be no larger than a value around 60 to 64.
|
// The message max length should be no larger than a value around 60 to 64.
|
||||||
#define MESSAGE_MAX_LEN 60
|
#define MESSAGE_MAX_LEN 60
|
||||||
|
|
||||||
|
// The is the most characters you can enter at a keyboard prompt.
|
||||||
|
#define KEYBOARD_MAX_LEN 40
|
||||||
|
|
||||||
// How often to send a beacon.
|
// How often to send a beacon.
|
||||||
#define BEACON_DURATION 3
|
#define BEACON_DURATION 3
|
||||||
|
|
||||||
@ -154,6 +157,7 @@ typedef enum {
|
|||||||
ScreenPlayingGame,
|
ScreenPlayingGame,
|
||||||
ScreenError,
|
ScreenError,
|
||||||
ScreenJoinGame,
|
ScreenJoinGame,
|
||||||
|
ScreenChooseSocial,
|
||||||
ScreenEditMessage,
|
ScreenEditMessage,
|
||||||
ScreenPastGames,
|
ScreenPastGames,
|
||||||
} ScreenState;
|
} ScreenState;
|
||||||
@ -182,23 +186,25 @@ typedef enum {
|
|||||||
} GameEventType;
|
} GameEventType;
|
||||||
|
|
||||||
static const char* contact_list[] = {
|
static const char* contact_list[] = {
|
||||||
"CBuy me a coffee",
|
"_(Flipper name only)",
|
||||||
"DDiscord",
|
"AAlias",
|
||||||
"EEmpty",
|
"CBuyMeACoffee.com",
|
||||||
"FFacebook",
|
"DDiscord handle",
|
||||||
|
"EEtsy shop",
|
||||||
|
"FFacebook username",
|
||||||
"GGithub",
|
"GGithub",
|
||||||
"HHandle",
|
"IInstagram username",
|
||||||
"IInstagram",
|
"LLinkedin profile",
|
||||||
"LLinkedin",
|
"MMobile number",
|
||||||
"MMobile",
|
|
||||||
"NName",
|
"NName",
|
||||||
"PPinterest",
|
"PPinterest username",
|
||||||
"RReddit",
|
"RReddit username",
|
||||||
"KTikTok",
|
"KTikTok handle",
|
||||||
"UTinyUrl.com",
|
"UTinyUrl.com",
|
||||||
"WTwitch",
|
"WTwitch id",
|
||||||
"TTwitter",
|
"TTwitter handle",
|
||||||
"YYouTube",
|
"VYouTube video",
|
||||||
|
"YYouTube channel",
|
||||||
};
|
};
|
||||||
|
|
||||||
// An item in the event queue has both the type and its associated data.
|
// An item in the event queue has both the type and its associated data.
|
||||||
@ -255,6 +261,11 @@ typedef struct {
|
|||||||
FuriString* local_contact;
|
FuriString* local_contact;
|
||||||
struct PlayerStats* player_stats;
|
struct PlayerStats* player_stats;
|
||||||
struct PlayerStats* viewing_player_stats;
|
struct PlayerStats* viewing_player_stats;
|
||||||
|
FuriString* keyboard_data;
|
||||||
|
FuriString* keyboard_heading;
|
||||||
|
int keyboard_row;
|
||||||
|
int keyboard_col;
|
||||||
|
int social_line;
|
||||||
} GameData;
|
} GameData;
|
||||||
|
|
||||||
// This is our application context.
|
// This is our application context.
|
||||||
|
Loading…
Reference in New Issue
Block a user