mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 10:07:38 -04:00
Implement dart scorer plugin application.
Edit: - Add name to credits - Add entry in manual Change-Id: I0e0b062e001ae9134db3ee6e4fba21e93ddd04ee
This commit is contained in:
parent
d50470bc7d
commit
49910eca4b
6 changed files with 623 additions and 0 deletions
|
@ -22,6 +22,7 @@ clock,apps
|
|||
codebuster,games
|
||||
credits,viewers
|
||||
cube,demos
|
||||
dart_scorer,apps
|
||||
db_commit,apps
|
||||
db_folder_select,viewers
|
||||
demystify,demos
|
||||
|
|
|
@ -9,6 +9,7 @@ tagcache/tagcache.c
|
|||
chessclock.c
|
||||
credits.c
|
||||
cube.c
|
||||
dart_scorer.c
|
||||
dict.c
|
||||
jackpot.c
|
||||
keybox.c
|
||||
|
|
601
apps/plugins/dart_scorer.c
Normal file
601
apps/plugins/dart_scorer.c
Normal file
|
@ -0,0 +1,601 @@
|
|||
#include "plugin.h"
|
||||
#include "lib/display_text.h"
|
||||
#include "lib/helper.h"
|
||||
#include "lib/playback_control.h"
|
||||
#include "lib/pluginlib_exit.h"
|
||||
#include "lib/pluginlib_actions.h"
|
||||
|
||||
#define BUTTON_ROWS 6
|
||||
#define BUTTON_COLS 5
|
||||
|
||||
#define REC_HEIGHT (int)(LCD_HEIGHT / (BUTTON_ROWS + 1))
|
||||
#define REC_WIDTH (int)(LCD_WIDTH / BUTTON_COLS)
|
||||
|
||||
#define Y_7_POS (LCD_HEIGHT) /* Leave room for the border */
|
||||
#define Y_6_POS (Y_7_POS - REC_HEIGHT) /* y6 = 63 */
|
||||
#define Y_5_POS (Y_6_POS - REC_HEIGHT) /* y5 = 53 */
|
||||
#define Y_4_POS (Y_5_POS - REC_HEIGHT) /* y4 = 43 */
|
||||
#define Y_3_POS (Y_4_POS - REC_HEIGHT) /* y3 = 33 */
|
||||
#define Y_2_POS (Y_3_POS - REC_HEIGHT) /* y2 = 23 */
|
||||
#define Y_1_POS (Y_2_POS - REC_HEIGHT) /* y1 = 13 */
|
||||
#define Y_0_POS 0 /* y0 = 0 */
|
||||
|
||||
#define X_0_POS 0 /* x0 = 0 */
|
||||
#define X_1_POS (X_0_POS + REC_WIDTH) /* x1 = 22 */
|
||||
#define X_2_POS (X_1_POS + REC_WIDTH) /* x2 = 44 */
|
||||
#define X_3_POS (X_2_POS + REC_WIDTH) /* x3 = 66 */
|
||||
#define X_4_POS (X_3_POS + REC_WIDTH) /* x4 = 88 */
|
||||
#define X_5_POS (X_4_POS + REC_WIDTH) /* x5 = 110, column 111 left blank */
|
||||
|
||||
#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
|
||||
#define DARTS_QUIT PLA_SELECT_REPEAT
|
||||
#else
|
||||
#define DARTS_QUIT PLA_CANCEL
|
||||
#endif
|
||||
#define DARTS_SELECT PLA_SELECT
|
||||
#define DARTS_RIGHT PLA_RIGHT
|
||||
#define DARTS_LEFT PLA_LEFT
|
||||
#define DARTS_UP PLA_UP
|
||||
#define DARTS_DOWN PLA_DOWN
|
||||
#define DARTS_RRIGHT PLA_RIGHT_REPEAT
|
||||
#define DARTS_RLEFT PLA_LEFT_REPEAT
|
||||
#define DARTS_RUP PLA_UP_REPEAT
|
||||
#define DARTS_RDOWN PLA_DOWN_REPEAT
|
||||
|
||||
#define RESUME_FILE PLUGIN_GAMES_DATA_DIR "/dart_scorer.save"
|
||||
/* leave first line blank on bitmap display, for pause icon */
|
||||
#define FIRST_LINE 1
|
||||
|
||||
#define NUM_PLAYERS 2
|
||||
#define MAX_UNDO 100
|
||||
|
||||
static const struct button_mapping *plugin_contexts[] = {pla_main_ctx};
|
||||
|
||||
/* game data structures */
|
||||
enum game_mode
|
||||
{
|
||||
five,
|
||||
three
|
||||
};
|
||||
static struct settings_struct
|
||||
{
|
||||
enum game_mode mode;
|
||||
int scores[2];
|
||||
bool turn;
|
||||
int throws;
|
||||
int history[MAX_UNDO];
|
||||
int history_ptr;
|
||||
} settings;
|
||||
|
||||
/* temporary data */
|
||||
static bool loaded = false; /* has a save been loaded? */
|
||||
int btn_row, btn_col; /* current position index for button */
|
||||
int prev_btn_row, prev_btn_col; /* previous cursor position */
|
||||
unsigned char *buttonChar[6][5] = {
|
||||
{"", "Single", "Double", "Triple", ""},
|
||||
{"1", "2", "3", "4", "5"},
|
||||
{"6", "7", "8", "9", "10"},
|
||||
{"11", "12", "13", "14", "15"},
|
||||
{"16", "17", "18", "19", "20"},
|
||||
{"", "Missed", "Bull", "Undo", ""}};
|
||||
int modifier;
|
||||
|
||||
static int do_dart_scorer_pause_menu(void);
|
||||
static void drawButtons(void);
|
||||
|
||||
/* First, increases *dimen1 by dimen1_delta modulo dimen1_modulo.
|
||||
If dimen1 wraps, increases *dimen2 by dimen2_delta modulo dimen2_modulo.
|
||||
*/
|
||||
static void move_with_wrap_and_shift(
|
||||
int *dimen1, int dimen1_delta, int dimen1_modulo,
|
||||
int *dimen2, int dimen2_delta, int dimen2_modulo)
|
||||
{
|
||||
bool wrapped = false;
|
||||
|
||||
*dimen1 += dimen1_delta;
|
||||
if (*dimen1 < 0)
|
||||
{
|
||||
*dimen1 = dimen1_modulo - 1;
|
||||
wrapped = true;
|
||||
}
|
||||
else if (*dimen1 >= dimen1_modulo)
|
||||
{
|
||||
*dimen1 = 0;
|
||||
wrapped = true;
|
||||
}
|
||||
|
||||
if (wrapped)
|
||||
{
|
||||
/* Make the dividend always positive to be sure about the result.
|
||||
Adding dimen2_modulo does not change it since we do it modulo. */
|
||||
*dimen2 = (*dimen2 + dimen2_modulo + dimen2_delta) % dimen2_modulo;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawButtons()
|
||||
{
|
||||
int i, j, w, h;
|
||||
for (i = 0; i <= 5; i++)
|
||||
{
|
||||
for (j = 0; j <= 4; j++)
|
||||
{
|
||||
unsigned char button_text[16];
|
||||
char *selected_prefix = (i == 0 && modifier > 0 && j == modifier) ? "*" : "";
|
||||
rb->snprintf(button_text, sizeof(button_text), "%s%s", selected_prefix, buttonChar[i][j]);
|
||||
rb->lcd_getstringsize(button_text, &w, &h);
|
||||
if (i == btn_row && j == btn_col) /* selected item */
|
||||
rb->lcd_set_drawmode(DRMODE_SOLID);
|
||||
else
|
||||
rb->lcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
|
||||
rb->lcd_fillrect(X_0_POS + j * REC_WIDTH,
|
||||
Y_1_POS + i * REC_HEIGHT,
|
||||
REC_WIDTH, REC_HEIGHT + 1);
|
||||
if (i == btn_row && j == btn_col) /* selected item */
|
||||
rb->lcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
|
||||
else
|
||||
rb->lcd_set_drawmode(DRMODE_SOLID);
|
||||
rb->lcd_putsxy(X_0_POS + j * REC_WIDTH + (REC_WIDTH - w) / 2,
|
||||
Y_1_POS + i * REC_HEIGHT + (REC_HEIGHT - h) / 2 + 1,
|
||||
button_text);
|
||||
}
|
||||
}
|
||||
rb->lcd_set_drawmode(DRMODE_SOLID);
|
||||
}
|
||||
|
||||
static void draw(void)
|
||||
{
|
||||
rb->lcd_clear_display();
|
||||
|
||||
char buf[32];
|
||||
|
||||
int x = 5;
|
||||
int y = 10;
|
||||
for (int i = 0; i < NUM_PLAYERS; ++i, x = x + 95)
|
||||
{
|
||||
char *turn_marker = (i == settings.turn) ? "*" : "";
|
||||
rb->snprintf(buf, sizeof(buf), "%sPlayer %d: %d", turn_marker, i + 1, settings.scores[i]);
|
||||
rb->lcd_putsxy(x, y, buf);
|
||||
}
|
||||
int throws_x = (LCD_WIDTH / 2) - 10;
|
||||
char throws_buf[3];
|
||||
for (int i = 0; i < settings.throws; ++i, throws_x += 5)
|
||||
{
|
||||
rb->strcat(throws_buf, "1");
|
||||
rb->lcd_putsxy(throws_x, y, "|");
|
||||
}
|
||||
|
||||
drawButtons();
|
||||
|
||||
rb->lcd_update();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* save_game() saves the current game state.
|
||||
******************************************************************************/
|
||||
static void save_game(void)
|
||||
{
|
||||
int fd = rb->open(RESUME_FILE, O_WRONLY | O_CREAT, 0666);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
rb->write(fd, &settings, sizeof(struct settings_struct));
|
||||
|
||||
rb->close(fd);
|
||||
rb->lcd_update();
|
||||
}
|
||||
|
||||
/* load_game() loads the saved game and returns load success.*/
|
||||
static bool load_game(void)
|
||||
{
|
||||
signed int fd;
|
||||
bool loaded = false;
|
||||
|
||||
/* open game file */
|
||||
fd = rb->open(RESUME_FILE, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
/* read in saved game */
|
||||
if (rb->read(fd, &settings, sizeof(struct settings_struct)) == (long)sizeof(struct settings_struct))
|
||||
{
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
rb->close(fd);
|
||||
|
||||
return loaded;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* asks the user if they wish to quit */
|
||||
static bool confirm_quit(void)
|
||||
{
|
||||
const struct text_message prompt = {(const char *[]){"Are you sure?", "This will clear your current game."}, 2};
|
||||
enum yesno_res response = rb->gui_syncyesno_run(&prompt, NULL, NULL);
|
||||
if (response == YESNO_NO)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/* displays the help text */
|
||||
static bool do_help(void)
|
||||
{
|
||||
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
rb->lcd_set_foreground(LCD_WHITE);
|
||||
rb->lcd_set_background(LCD_BLACK);
|
||||
#endif
|
||||
|
||||
rb->lcd_setfont(FONT_UI);
|
||||
|
||||
static char *help_text[] = {"Dart Scorer", "", "", "Keep score of your darts game."};
|
||||
|
||||
struct style_text style[] = {
|
||||
{0, TEXT_CENTER | TEXT_UNDERLINE},
|
||||
};
|
||||
|
||||
return display_text(ARRAYLEN(help_text), help_text, style, NULL, true);
|
||||
}
|
||||
|
||||
static void undo(void)
|
||||
{
|
||||
if (!settings.history_ptr)
|
||||
{
|
||||
rb->splash(HZ * 2, "Out of undos!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* jumping back to previous player? */
|
||||
int turn = settings.throws == 3 ? !settings.turn : settings.turn;
|
||||
if (turn != settings.turn)
|
||||
{
|
||||
settings.throws = 0;
|
||||
settings.turn ^= true;
|
||||
}
|
||||
|
||||
if (settings.history[settings.history_ptr - 1] >= 0)
|
||||
{
|
||||
settings.scores[turn] += settings.history[--settings.history_ptr];
|
||||
++settings.throws;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
negative history means we bust. negative filled for all skipped throws
|
||||
from being bust so consume back until no more
|
||||
*/
|
||||
for (; settings.throws < 3 && settings.history[settings.history_ptr - 1] < 0; --settings.history_ptr, ++settings.throws)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void init_game(bool newgame)
|
||||
{
|
||||
if (newgame)
|
||||
{
|
||||
/* initialize the game context */
|
||||
modifier = 1;
|
||||
btn_row = 1;
|
||||
btn_col = 0;
|
||||
|
||||
int game_mode = -1;
|
||||
MENUITEM_STRINGLIST(menu, "Game Mode", NULL, "501", "301");
|
||||
while (game_mode < 0)
|
||||
{
|
||||
switch (rb->do_menu(&menu, &game_mode, NULL, false))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
settings.mode = five;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
settings.mode = three;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_PLAYERS; ++i)
|
||||
{
|
||||
settings.scores[i] = (settings.mode == five) ? 501 : 301;
|
||||
}
|
||||
settings.turn = false;
|
||||
settings.throws = 3;
|
||||
settings.history_ptr = 0;
|
||||
rb->lcd_clear_display();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* main game loop */
|
||||
static enum plugin_status do_game(bool newgame)
|
||||
{
|
||||
init_game(newgame);
|
||||
draw();
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* wait for button press */
|
||||
int button = pluginlib_getaction(-1, plugin_contexts, ARRAYLEN(plugin_contexts));
|
||||
unsigned char *selected = buttonChar[btn_row][btn_col];
|
||||
switch (button)
|
||||
{
|
||||
case DARTS_SELECT:
|
||||
if ((!rb->strcmp(selected, "")) || (!rb->strcmp(selected, "Single")))
|
||||
modifier = 1;
|
||||
else if (!rb->strcmp(selected, "Double"))
|
||||
modifier = 2;
|
||||
else if (!rb->strcmp(selected, "Triple"))
|
||||
modifier = 3;
|
||||
else if (!rb->strcmp(selected, "Undo"))
|
||||
{
|
||||
undo();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* main logic of score keeping */
|
||||
if (modifier == 0)
|
||||
modifier = 1;
|
||||
int hit = (!rb->strcmp(selected, "Bull")) ? 25 : rb->atoi(selected);
|
||||
if (hit == 25 && modifier == 3)
|
||||
{
|
||||
/* no triple bullseye! */
|
||||
rb->splash(HZ * 2, "Triple Bull... Don't be silly!");
|
||||
continue;
|
||||
}
|
||||
hit *= modifier;
|
||||
if (hit > settings.scores[settings.turn])
|
||||
{
|
||||
rb->splash(HZ * 2, "Bust! End of turn.");
|
||||
for (int i = 0; i < settings.throws; ++i)
|
||||
settings.history[settings.history_ptr++] = -1;
|
||||
settings.throws = 0;
|
||||
}
|
||||
else if (hit == settings.scores[settings.turn] - 1)
|
||||
{
|
||||
rb->splash(HZ * 2, "1 left! Must checkout with a double. End of turn.");
|
||||
for (int i = 0; i < settings.throws; ++i)
|
||||
settings.history[settings.history_ptr++] = -1;
|
||||
settings.throws = 0;
|
||||
}
|
||||
else if (hit == settings.scores[settings.turn] && modifier != 2)
|
||||
{
|
||||
rb->splash(HZ * 2, "Must checkout with a double! End of turn.");
|
||||
for (int i = 0; i < settings.throws; ++i)
|
||||
settings.history[settings.history_ptr++] = -1;
|
||||
settings.throws = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.scores[settings.turn] -= hit;
|
||||
--settings.throws;
|
||||
settings.history[settings.history_ptr++] = hit;
|
||||
modifier = 1;
|
||||
if (!settings.scores[settings.turn])
|
||||
goto GAMEOVER;
|
||||
}
|
||||
|
||||
if (!settings.throws)
|
||||
{
|
||||
settings.throws = 3;
|
||||
settings.turn ^= true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DARTS_LEFT:
|
||||
case DARTS_RLEFT:
|
||||
move_with_wrap_and_shift(
|
||||
&btn_col, -1, BUTTON_COLS,
|
||||
&btn_row, 0, BUTTON_ROWS);
|
||||
break;
|
||||
case DARTS_RIGHT:
|
||||
case DARTS_RRIGHT:
|
||||
move_with_wrap_and_shift(
|
||||
&btn_col, 1, BUTTON_COLS,
|
||||
&btn_row, 0, BUTTON_ROWS);
|
||||
break;
|
||||
#ifdef DARTS_UP
|
||||
case DARTS_UP:
|
||||
case DARTS_RUP:
|
||||
#ifdef HAVE_SCROLLWHEEL
|
||||
case PLA_SCROLL_BACK:
|
||||
case PLA_SCROLL_BACK_REPEAT:
|
||||
#endif
|
||||
move_with_wrap_and_shift(
|
||||
&btn_row, -1, BUTTON_ROWS,
|
||||
&btn_col, 0, BUTTON_COLS);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DARTS_DOWN
|
||||
case DARTS_DOWN:
|
||||
case DARTS_RDOWN:
|
||||
#ifdef HAVE_SCROLLWHEEL
|
||||
case PLA_SCROLL_FWD:
|
||||
case PLA_SCROLL_FWD_REPEAT:
|
||||
#endif
|
||||
move_with_wrap_and_shift(
|
||||
&btn_row, 1, BUTTON_ROWS,
|
||||
&btn_col, 0, BUTTON_COLS);
|
||||
break;
|
||||
#endif
|
||||
case DARTS_QUIT:
|
||||
switch (do_dart_scorer_pause_menu())
|
||||
{
|
||||
case 0: /* resume */
|
||||
break;
|
||||
case 1:
|
||||
init_game(true);
|
||||
continue;
|
||||
case 2: /* quit w/o saving */
|
||||
rb->remove(RESUME_FILE);
|
||||
return PLUGIN_ERROR;
|
||||
case 3: /* save & quit */
|
||||
save_game();
|
||||
return PLUGIN_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
exit_on_usb(button); /* handle poweroff and USB */
|
||||
break;
|
||||
}
|
||||
}
|
||||
draw();
|
||||
}
|
||||
|
||||
GAMEOVER:
|
||||
rb->splashf(HZ * 3, "Gameover. Player %d wins!", settings.turn + 1);
|
||||
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
/* decide if this_item should be shown in the main menu */
|
||||
/* used to hide resume option when there is no save */
|
||||
static int mainmenu_cb(int action,
|
||||
const struct menu_item_ex *this_item,
|
||||
struct gui_synclist *this_list)
|
||||
{
|
||||
(void)this_list;
|
||||
int idx = ((intptr_t)this_item);
|
||||
if (action == ACTION_REQUEST_MENUITEM && !loaded && (idx == 0 || idx == 5))
|
||||
return ACTION_EXIT_MENUITEM;
|
||||
return action;
|
||||
}
|
||||
|
||||
/* show the pause menu */
|
||||
static int do_dart_scorer_pause_menu(void)
|
||||
{
|
||||
int sel = 0;
|
||||
MENUITEM_STRINGLIST(menu, "Dart Scorer", NULL,
|
||||
"Resume Game",
|
||||
"Start New Game",
|
||||
"Playback Control",
|
||||
"Help",
|
||||
"Quit without Saving",
|
||||
"Quit");
|
||||
while (1)
|
||||
{
|
||||
switch (rb->do_menu(&menu, &sel, NULL, false))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
rb->splash(HZ * 2, "Resume");
|
||||
return 0;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (!confirm_quit())
|
||||
break;
|
||||
else
|
||||
{
|
||||
rb->splash(HZ * 2, "New Game");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
playback_control(NULL);
|
||||
break;
|
||||
case 3:
|
||||
do_help();
|
||||
break;
|
||||
case 4: /* quit w/o saving */
|
||||
{
|
||||
if (!confirm_quit())
|
||||
break;
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
return 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* show the main menu */
|
||||
static enum plugin_status do_dart_scorer_menu(void)
|
||||
{
|
||||
int sel = 0;
|
||||
loaded = load_game();
|
||||
MENUITEM_STRINGLIST(menu,
|
||||
"Dart Scorer Menu",
|
||||
mainmenu_cb,
|
||||
"Resume Game",
|
||||
"Start New Game",
|
||||
"Playback Control",
|
||||
"Help",
|
||||
"Quit without Saving",
|
||||
"Quit");
|
||||
while (true)
|
||||
{
|
||||
switch (rb->do_menu(&menu, &sel, NULL, false))
|
||||
{
|
||||
case 0: /* Start new game or resume a game */
|
||||
case 1:
|
||||
{
|
||||
if (sel == 1 && loaded)
|
||||
{
|
||||
if (!confirm_quit())
|
||||
break;
|
||||
}
|
||||
enum plugin_status ret = do_game(sel == 1);
|
||||
switch (ret)
|
||||
{
|
||||
case PLUGIN_OK:
|
||||
{
|
||||
loaded = false;
|
||||
rb->remove(RESUME_FILE);
|
||||
break;
|
||||
}
|
||||
case PLUGIN_USB_CONNECTED:
|
||||
save_game();
|
||||
return ret;
|
||||
case PLUGIN_ERROR: /* exit without menu */
|
||||
return PLUGIN_OK;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
playback_control(NULL);
|
||||
break;
|
||||
case 3:
|
||||
do_help();
|
||||
break;
|
||||
case 4:
|
||||
if (confirm_quit())
|
||||
return PLUGIN_OK;
|
||||
break;
|
||||
case 5:
|
||||
if (loaded)
|
||||
save_game();
|
||||
return PLUGIN_OK;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* prepares for exit */
|
||||
static void cleanup(void)
|
||||
{
|
||||
backlight_use_settings();
|
||||
}
|
||||
|
||||
enum plugin_status plugin_start(const void *parameter)
|
||||
{
|
||||
(void)parameter;
|
||||
/* now start the game menu */
|
||||
enum plugin_status ret = do_dart_scorer_menu();
|
||||
cleanup();
|
||||
return ret;
|
||||
}
|
|
@ -716,6 +716,7 @@ Roman Artiukhin
|
|||
Richard Goedeken
|
||||
Mihaly 'Hermit' Horvath
|
||||
Uwe Kleine-König
|
||||
JJ Style
|
||||
|
||||
The libmad team
|
||||
The wavpack team
|
||||
|
|
17
manual/plugins/dart_scorer.tex
Normal file
17
manual/plugins/dart_scorer.tex
Normal file
|
@ -0,0 +1,17 @@
|
|||
\subsection{Dart Scorer}
|
||||
|
||||
The dart scorer plugin allows scoring a game of darts (301/501) for two players. It supports modifiers for double/triple hits, bullseye, undo, and game saving and resuming.
|
||||
|
||||
\begin{btnmap}
|
||||
\PluginUp, \PluginDown, \PluginLeft, \PluginRight
|
||||
\opt{HAVEREMOTEKEYMAP}{& \PluginRCUp, \PluginRCDown, \PluginRCLeft, \PluginRCRight}
|
||||
& Move cursor\\
|
||||
|
||||
\PluginSelect
|
||||
& Select button under cursor\\
|
||||
|
||||
\nopt{IPOD_4G_PAD,IPOD_3G_PAD}{\PluginCancel}
|
||||
\opt{IPOD_4G_PAD,IPOD_3G_PAD}{Long \ButtonSelect}
|
||||
\opt{HAVEREMOTEKEYMAP}{& \PluginRCCancel}
|
||||
& Go to menu\\
|
||||
\end{btnmap}
|
|
@ -246,6 +246,8 @@ option from the \setting{Context Menu} (see \reference{ref:Contextmenu}).}
|
|||
|
||||
\opt{rtc}{\input{plugins/clock.tex}}
|
||||
|
||||
\input{plugins/dart_scorer.tex}
|
||||
|
||||
\input{plugins/dict.tex}
|
||||
|
||||
\input{plugins/disktidy.tex}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue