rockbox/apps/plugins/dice.c
Christian Soffke faa2cb9942 plugins: Improve usability of iPod keymaps
- Reduce need to press multiple buttons at
the same time to quit a plugin

- Have "Menu" be default way to quit plugins or
to access plugin menu

- Fall back to (Long) "Select" or Long "Menu"
in cases where Menu button isn't available
(e.g. in ImageViewer and many games)

out of scope:
boomshine, lua_scripts, Rockpaint,
Doom, Duke3D, Pacbox, Quake,
Sgt-Puzzles, Wolf3D, XWorld,
Minesweeper, Pixel Painter, Spacerocks

Change-Id: I6d4dc7174695fe4b8ee9cbaccb21bdbfe6af5c48
2022-12-29 04:39:22 +01:00

221 lines
6.7 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Brandon Low
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "lib/pluginlib_actions.h"
#include "lib/configfile.h"
#include "lib/playback_control.h"
#define MAX_DICES 12
#define INITIAL_NB_DICES 1
#define INITIAL_NB_SIDES 2 /* corresponds to 6 sides in the array */
#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
|| (CONFIG_KEYPAD == IPOD_3G_PAD) \
|| (CONFIG_KEYPAD == IPOD_4G_PAD)
#define DICE_QUIT PLA_UP
#else
#define DICE_QUIT PLA_CANCEL
#endif
#define DICE_ROLL PLA_SELECT
#define CFG_FILE "dice.cfg"
const struct button_mapping* plugin_contexts[]={pla_main_ctx};
struct dices
{
int values[MAX_DICES];
int total;
int nb_dices;
int nb_sides;
};
#define PRINT_BUFFER_LENGTH MAX_DICES*4
static struct dices dice;
static int sides_index;
static struct opt_items nb_sides_option[8] = {
{ "3", TALK_ID(3, UNIT_INT) },
{ "4", TALK_ID(4, UNIT_INT) },
{ "6", TALK_ID(6, UNIT_INT) },
{ "8", TALK_ID(8, UNIT_INT) },
{ "10", TALK_ID(10, UNIT_INT) },
{ "12", TALK_ID(12, UNIT_INT) },
{ "20", TALK_ID(20, UNIT_INT) },
{ "100", TALK_ID(100, UNIT_INT) }
};
static int nb_sides_values[] = { 3, 4, 6, 8, 10, 12, 20, 100 };
static char *sides_conf[] = {"3", "4", "6", "8", "10", "12", "20", "100" };
static struct configdata config[] =
{
{TYPE_INT, 0, MAX_DICES, { .int_p = &dice.nb_dices}, "dice count", NULL},
{TYPE_ENUM, 0, 8, { .int_p = &sides_index }, "side count", sides_conf}
};
static void dice_init(struct dices* dice);
static void dice_roll(struct dices* dice);
static void dice_print(struct dices* dice, struct screen* display);
static bool dice_menu(struct dices* dice);
/* plugin entry point */
enum plugin_status plugin_start(const void* parameter) {
(void)parameter;
int action;
dice_init(&dice);
rb->srand(*rb->current_tick);
configfile_load(CFG_FILE, config, 2, 0);
dice.nb_sides = nb_sides_values[sides_index];
if(!dice_menu(&dice))
{
configfile_save(CFG_FILE, config, 2, 0);
return PLUGIN_OK;
}
configfile_save(CFG_FILE, config, 2, 0);
dice_roll(&dice);
FOR_NB_SCREENS(i)
dice_print( &dice, rb->screens[i] );
while(true) {
action = pluginlib_getaction(TIMEOUT_BLOCK,
plugin_contexts, ARRAYLEN(plugin_contexts));
switch(action) {
case DICE_ROLL:
dice_roll(&dice);
FOR_NB_SCREENS(i)
dice_print( &dice, rb->screens[i] );
break;
case DICE_QUIT:
return PLUGIN_OK;
}
}
}
static void dice_init(struct dices* dice){
dice->nb_dices=INITIAL_NB_DICES;
sides_index=INITIAL_NB_SIDES;
}
static void dice_roll(struct dices* dice) {
int i;
dice->total = 0;
for (i=0; i<dice->nb_dices; i++) {
dice->values[i] = rb->rand()%dice->nb_sides + 1;
dice->total+=dice->values[i];
}
}
static void dice_print_string_buffer(struct dices* dice, char* buffer,
int start, int end){
int i, written;
for (i=start; i<end; i++) {
written=rb->snprintf(buffer, PRINT_BUFFER_LENGTH,
" %3d", dice->values[i]);
buffer=&(buffer[written]);
}
}
static void dice_print(struct dices* dice, struct screen* display){
char buffer[PRINT_BUFFER_LENGTH];
/* display characteristics */
int char_height, char_width;
display->getstringsize("M", &char_width, &char_height);
int display_nb_row=display->getheight()/char_height;
int display_nb_col=display->getwidth()/char_width;
int nb_dices_per_line=display_nb_col/4;/* 4 char per dice displayed*/
if(!nb_dices_per_line)
nb_dices_per_line++;
int nb_lines_required=dice->nb_dices/nb_dices_per_line;
int current_row=0;
if(dice->nb_dices%nb_dices_per_line!=0)
nb_lines_required++;
display->clear_display();
if(display_nb_row<nb_lines_required){
/* Put everything on the same scrolling line */
dice_print_string_buffer(dice, buffer, 0, dice->nb_dices);
display->puts_scroll(0, current_row, buffer);
current_row++;
}else{
int start=0;
int end=0;
for(;current_row<nb_lines_required;current_row++){
end=start+nb_dices_per_line;
if(end>dice->nb_dices)
end=dice->nb_dices;
dice_print_string_buffer(dice, buffer, start, end);
display->puts(0, current_row, buffer);
start=end;
}
}
rb->snprintf(buffer, PRINT_BUFFER_LENGTH, "Total: %d", dice->total);
display->puts_scroll(0, current_row, buffer);
display->update();
}
static bool dice_menu(struct dices * dice) {
int selection;
bool menu_quit = false, result = false;
MENUITEM_STRINGLIST(menu, "Dice Menu", NULL,
"Roll Dice",
"Number of Dice", "Number of Sides",
"Playback Control", "Quit");
while (!menu_quit) {
switch(rb->do_menu(&menu, &selection, NULL, false)){
case 0:
menu_quit = true;
result = true;
break;
case 1:
rb->set_int("Number of Dice", "", UNIT_INT, &(dice->nb_dices),
NULL, 1, 1, MAX_DICES, NULL );
break;
case 2:
rb->set_option("Number of Sides", &sides_index, INT,
nb_sides_option,
sizeof(nb_sides_values)/sizeof(int), NULL);
dice->nb_sides=nb_sides_values[sides_index];
break;
case 3:
playback_control(NULL);
break;
default:
menu_quit = true;
result = false;
break;
}
}
return result;
}