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.
|
||||
- Allow viewing past games/scores.
|
||||
- A join ACK removes it from the list of available games.
|
||||
- Config - Allow changing hard-coded CONTACT_INFO message.
|
||||
|
||||
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.
|
||||
- Write tutorial.
|
||||
- Add game ending animations.
|
||||
@ -59,14 +60,16 @@ These directions assume you are starting at the flipper desktop. If not, please
|
||||
- Do the same steps on your second Flipper.
|
||||
|
||||
- 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.
|
||||
- click OK button to start game.
|
||||
|
||||
- On Flipper 2, choose "Join game".
|
||||
|
||||
- select the same valid frequency as Flipper 1.
|
||||
- "game none" should change to show the game number from Flipper 1 & its name.
|
||||
-click OK button to join game.
|
||||
- "game none" should change to show the game number from Flipper 1 & its name.
|
||||
-click OK button to join game.
|
||||
|
||||
- Once two players are joined:
|
||||
|
||||
@ -120,31 +123,32 @@ sudo hackrf_transfer -r flipper-chat.rf -f 433920000 -s 8000000 -x 47
|
||||
- rock_paper_scissors.c
|
||||
- This is the game applcation.
|
||||
|
||||
|
||||
## Example data
|
||||
|
||||
- Beacon for game 042:
|
||||
RPS:BA042:Lumyphut
|
||||
RPS:BA042:Lumyphut
|
||||
|
||||
- Join game 042:
|
||||
RPS:JA042NYourNameHere :Lumyphut
|
||||
RPS:JA042NYourNameHere :Lumyphut
|
||||
|
||||
- Join-ack for game 042:
|
||||
RPS:AA042NYourNameHere :Lumyphut
|
||||
RPS:AA042NYourNameHere :Lumyphut
|
||||
|
||||
- Count 1 for game 042:
|
||||
RPS:MA0421:Lumyphut
|
||||
RPS:MA0421:Lumyphut
|
||||
|
||||
- Count 2 for game 042:
|
||||
RPS:MA0422:Lumyphut
|
||||
RPS:MA0422:Lumyphut
|
||||
|
||||
- Rock for game 042:
|
||||
RPS:MA042R:Lumyphut
|
||||
RPS:MA042R:Lumyphut
|
||||
|
||||
- Paper for game 042:
|
||||
RPS:MA042P:Lumyphut
|
||||
RPS:MA042P:Lumyphut
|
||||
|
||||
- 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, 27, AlignLeft, AlignTop, "Join game");
|
||||
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) {
|
||||
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 render the UI on this callback thread.
|
||||
// @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);
|
||||
} else if(game_context->data->screen_state == ScreenPastGames) {
|
||||
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) {
|
||||
UNUSED(p);
|
||||
|
||||
UNUSED(contact_list);
|
||||
|
||||
// Configure our initial data.
|
||||
GameContext* game_context = malloc(sizeof(GameContext));
|
||||
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->local_contact = furi_string_alloc();
|
||||
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);
|
||||
|
||||
@ -1777,6 +1882,137 @@ int32_t rock_paper_scissors_app(void* p) {
|
||||
FURI_LOG_T(TAG, "No support for key %d", event.input.key);
|
||||
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(
|
||||
game_context->data->screen_state == ScreenMainMenu &&
|
||||
event.input.type == InputTypeShort) {
|
||||
@ -1829,7 +2065,7 @@ int32_t rock_paper_scissors_app(void* p) {
|
||||
game_context->data->player_stats;
|
||||
game_context->data->screen_state = ScreenPastGames;
|
||||
} else if(game_context->data->local_player == StateMainMenuMessage) {
|
||||
game_context->data->screen_state = ScreenEditMessage;
|
||||
game_context->data->screen_state = ScreenChooseSocial;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -26,12 +26,15 @@
|
||||
#define TAG "rock_paper_scissors_app"
|
||||
|
||||
// Name for "N", followed by your name without any spaces.
|
||||
#define CONTACT_INFO "NYourNameHere"
|
||||
#define CONTACT_INFO_NONE "E"
|
||||
#define CONTACT_INFO "_"
|
||||
#define CONTACT_INFO_NONE "_"
|
||||
|
||||
// The message max length should be no larger than a value around 60 to 64.
|
||||
#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.
|
||||
#define BEACON_DURATION 3
|
||||
|
||||
@ -154,6 +157,7 @@ typedef enum {
|
||||
ScreenPlayingGame,
|
||||
ScreenError,
|
||||
ScreenJoinGame,
|
||||
ScreenChooseSocial,
|
||||
ScreenEditMessage,
|
||||
ScreenPastGames,
|
||||
} ScreenState;
|
||||
@ -182,23 +186,25 @@ typedef enum {
|
||||
} GameEventType;
|
||||
|
||||
static const char* contact_list[] = {
|
||||
"CBuy me a coffee",
|
||||
"DDiscord",
|
||||
"EEmpty",
|
||||
"FFacebook",
|
||||
"_(Flipper name only)",
|
||||
"AAlias",
|
||||
"CBuyMeACoffee.com",
|
||||
"DDiscord handle",
|
||||
"EEtsy shop",
|
||||
"FFacebook username",
|
||||
"GGithub",
|
||||
"HHandle",
|
||||
"IInstagram",
|
||||
"LLinkedin",
|
||||
"MMobile",
|
||||
"IInstagram username",
|
||||
"LLinkedin profile",
|
||||
"MMobile number",
|
||||
"NName",
|
||||
"PPinterest",
|
||||
"RReddit",
|
||||
"KTikTok",
|
||||
"PPinterest username",
|
||||
"RReddit username",
|
||||
"KTikTok handle",
|
||||
"UTinyUrl.com",
|
||||
"WTwitch",
|
||||
"TTwitter",
|
||||
"YYouTube",
|
||||
"WTwitch id",
|
||||
"TTwitter handle",
|
||||
"VYouTube video",
|
||||
"YYouTube channel",
|
||||
};
|
||||
|
||||
// An item in the event queue has both the type and its associated data.
|
||||
@ -255,6 +261,11 @@ typedef struct {
|
||||
FuriString* local_contact;
|
||||
struct PlayerStats* player_stats;
|
||||
struct PlayerStats* viewing_player_stats;
|
||||
FuriString* keyboard_data;
|
||||
FuriString* keyboard_heading;
|
||||
int keyboard_row;
|
||||
int keyboard_col;
|
||||
int social_line;
|
||||
} GameData;
|
||||
|
||||
// This is our application context.
|
||||
|
Loading…
Reference in New Issue
Block a user