Index: tools/voice.pl =================================================================== --- tools/voice.pl (revision 18265) +++ tools/voice.pl (working copy) @@ -267,8 +267,8 @@ `$cmd`; } case "espeak" { - $cmd = "espeak $tts_engine_opts -w \"$output\""; - print("> $cmd\n") if $verbose; + $cmd = "speak $tts_engine_opts -w \"$output\""; + print("> $cmd\n"); open(ESPEAK, "|-:encoding(utf8)", $cmd); print ESPEAK $string . "\n"; close(ESPEAK); @@ -332,7 +332,7 @@ my $langfile = dirname($0) . '/../apps/lang/' . $language . '.lang'; my $id = ''; my $voice = ''; - my $cmd = "genlang -o -t=$target -e=$english $langfile 2>/dev/null"; + my $cmd = "genlang -o -t=$target -k=0 -e=$english $langfile 2>/dev/null"; my $pool_file; open(VOICEFONTIDS, ">:utf8", "voicefontids"); my $i = 0; @@ -389,7 +389,7 @@ if (defined($ENV{'POOL'})) { copy($mp3, $pool_file); } - unlink($wav); + #unlink($wav); } $voice = ""; $id = ""; @@ -468,7 +468,7 @@ # 500 seems to be a reasonable default for now encodewav($wav, $mp3, $encoder, $encoder_opts, $tts_object); synchronize($tts_object); - unlink($wav); + #unlink($wav); } } @@ -508,7 +508,7 @@ $t, $l, $e, $E, $s, $S); generateclips($l, $t, $e, $E, $s, $S); createvoice($l, $i); - deletemp3s(); + #deletemp3s(); } elsif ($C) { printf("Generating .talk clips\n Path: %s\n Language: %s\n Encoder (options): %s (%s)\n TTS Engine (options): %s (%s)\n", $ARGV[0], $l, $e, $E, $s, $S); Index: tools/genlang =================================================================== --- tools/genlang (revision 18265) +++ tools/genlang (working copy) @@ -11,7 +11,9 @@ # # binary version for the binary lang file -my $langversion = 4; # 3 was the latest one used in the v1 format +# 4 was the latest one used in the v2 format +# 3 was the latest one used in the v1 format +my $langversion = 5; # A note for future users and readers: The original v1 language system allowed # the build to create and use a different language than english built-in. We @@ -20,6 +22,22 @@ # figured it was boring and unnecessary to write support for now since we # don't use it anymore. +# This hash array and string must be kept in sync and the order must match. +my %user2num = + ('core' => 1, + 'blackjack' => 2, + 'chessbox' => 3, + 'chopper' => 4); + +my $plugin_enum = " +enum user_type { + USER_CORE, /* 0 */ + USER_BLACKJACK, /* 1 */ + USER_CHESSBOX, /* 2 */ + USER_CHOPPER /* 3 */ +}; +"; + if(!$ARGV[0]) { print < @@ -160,7 +178,7 @@ my @all= split(" *, *", $n); my $test; for $test (@all) { -# print "TEST ($debug) $target for $test\n"; + #print "TEST ($debug) $target for $test\n"; for my $part (split(":", $target)) { if(match($part, $test)) { $string = $v; @@ -187,6 +205,11 @@ parsetarget("voice", \$voice, @_); } +my $user; +sub user { + parsetarget("user", \$user, @_); +} + my %idmap; my %english; if($english) { @@ -196,6 +219,7 @@ my $idnum=0; # start with a true number my $vidnum=0x8000; # first voice id + my $pl_idnum=0; # first plugin lang id open(ENG, "<$english") || die "Error: can't open $english"; my @phrase; my $id; @@ -219,6 +243,11 @@ $idmap{$id}=$vidnum; $vidnum++; } + elsif($id =~ /^P_LANG_/) { + # Assign an ID number to this entry + $idmap{$id}=$pl_idnum; + $pl_idnum++; + } else { # Assign an ID number to this entry $idmap{$id}=$idnum; @@ -350,8 +379,10 @@ print @show; } -my $idcount; # counter for lang ID numbers -my $voiceid=0x8000; # counter for voice-only ID numbers +my $idcount; # counter for lang ID numbers +my $pl_idcount; # count for plugin lang ID numbers +my $voiceid=0x8000; # counter for voice-only ID numbers +my $pl_voiceid=0xB000; # counter for plugin voice-only ID numbers # # Now start the scanning of the selected language string @@ -360,6 +391,7 @@ open(LANG, "<$input") || die "Error: couldn't read language file named $input\n"; my @phrase; my $header = 1; +my @num_strings; while() { $line++; @@ -399,9 +431,9 @@ if($binary && !$english{$idstr}) { # $idstr doesn't exist for english, skip it\n"; } - elsif($dest =~ /^none\z/i) { - # "none" as dest (without quotes) means that this entire - # phrase is to be ignored + elsif($dest =~ /^none\z/i || $user =~ /^none\z/i) { + # "none" (without quotes) as dest or as the user + # means that this entire phrase is to be ignored } elsif(!$update) { # we don't do the fully detailed analysis when we "update" @@ -428,6 +460,13 @@ print STDERR "$input:$line:1: warning: voice before line lacks quotes ($voice)!\n"; $voice='""'; } + + my $user = $user2num{trim($phrase{'user'})}; + if(!$user) { + print STDERR "$input:$line:1: warning: unknown user!\n"; + printf ("%s %s\n", $idstr, $phase{'user'}); + $user = 1; + } # Use the ID name to figure out which id number range we # should use for this phrase. Voice-only strings are @@ -436,8 +475,18 @@ if($idstr =~ /^VOICE/) { $idnum = $voiceid++; } + elsif($idstr =~ /^P_VOICE/) { + $idnum = $pl_voiceid + $voiceid; + $pl_voiceid++; + } + elsif($idstr =~ /^P_LANG/) { + $idnum = $pl_idcount + $idcount; + $pl_idcount++; + $num_strings[$user]++; + } else { $idnum = $idcount++; + $num_strings[$user]++; } $id{$idstr} = $idnum; @@ -446,17 +495,19 @@ $source{$idstr}=$src; $dest{$idstr}=$dest; $voice{$idstr}=$voice; + $user{$idstr}=$user; if($verbose) { print "id: $phrase{id} ($idnum)\n"; print "source: $src\n"; print "dest: $dest\n"; print "voice: $voice\n"; + print "user: $user\n"; } - undef $src; undef $dest; undef $voice; + undef $user; undef %phrase; } @@ -514,42 +565,83 @@ if($prefix) { # We create a .c and .h file - open(HFILE, ">$prefix.h") || + open(HFILE_CORE, ">$prefix.h") || die "Error: couldn't create file $prefix.h\n"; - open(CFILE, ">$prefix.c") || - die "Error: couldn't create file $prefix.c\n"; - print HFILE <$prefix/lang\_$key.c") || + die "Error: couldn't create file $prefix\_$key.c\n"; + + my $end; + my $offset; + if($key eq "core") { + print CFILE <$prefix\_plugin.h") || + die "Error: couldn't create file $prefix\_plugin.h\n"; + foreach $key (sort {$user2num{$a} cmp $user2num{$b} } keys %user2num) { + if($key ne "core") { + printf HFILE_PLUGIN "extern const unsigned char $key\_language_builtin\[];\n"; } - - printf CFILE (" %s\n", $dest); } - -# Output end of string chunk - print CFILE <$binary") or die "Error: Can't create $binary"; binmode OUTF; printf OUTF ("\x1a%c%c", $langversion, $target_id); # magic lang file header + + # output the number of strings for each user + @hashkeys = keys(%user2num); + my $start = 0; + my $foffset = 3 + ($#hashkeys+1) * 6; + for $i (1 .. $#hashkeys+1) { + my $end = $start + $num_strings[$i] - 1; + my $size; + for $n ($start .. $end) { + $size += length(trim($dest{$idnum[$n]})) + 1; + #printf("%s %d %d\n", $dest{$idnum[$n]}, length($dest{$idnum[$n]}) + 1, $size+$foffset); + } + #printf ("%d-%d %d %d %d\n", $start, $end, $num_strings[$i], $size, $foffset); + $start = $end + 1; + printf OUTF ("%c%c%c%c%c%c", ($num_strings[$i] >> 8), ($num_strings[$i] & 0xff), + ($size >> 8), ($size & 0xff), ($foffset >> 8), ($foffset & 0xff)); + $foffset += $size; + } + + my $end_id = $idcount; + my $offset = -1; + for $j (1 .. 2) { + # loop over the target phrases + for $i (1 .. $end_id) { + my $name=$idnum[$i + $offset]; # get the ID + my $dest = $dest{$name}; # get the destination phrase - # loop over the target phrases - for $i (1 .. $idcount) { - my $name=$idnum[$i - 1]; # get the ID - my $dest = $dest{$name}; # get the destination phrase + if($dest) { + $dest =~ s/^\"(.*)\"\s*$/$1/g; # cut off quotes - if($dest) { - $dest =~ s/^\"(.*)\"\s*$/$1/g; # cut off quotes + # Now, make sure we get the number from the english sort order: + $idnum = $idmap{$name}; - # Now, make sure we get the number from the english sort order: - $idnum = $idmap{$name}; - - printf OUTF ("%c%c%s\x00", ($idnum>>8), ($idnum&0xff), $dest); + printf OUTF ("%c%c%s\x00", ($idnum>>8), ($idnum&0xff), $dest); + } } + $end_id = $pl_idcount; + $offset = $idcount - 1; } } elsif($voiceout) { @@ -642,13 +759,14 @@ # This loops over the strings in the translated language file order my @ids = ((0 .. ($idcount-1))); push @ids, (0x8000 .. ($voiceid-1)); + push @ids, (0xB000 .. ($pl_voiceid-1)); #for my $id (@ids) { # print "$id\n"; #} for $i (@ids) { - my $name=$idnum[$i]; # get the ID + my $name = $idnum[$i]; # get the ID my $dest = $voice{$name}; # get the destination voice string if($dest) { @@ -683,7 +801,7 @@ print "#$i ($o)\nid: $name\nvoice: $dest\n"; } - + } Index: tools/configure =================================================================== --- tools/configure (revision 18265) +++ tools/configure (working copy) @@ -492,11 +492,11 @@ NOISEFLOOR="500" TTS_OPTS=$SAPI_OPTS ;; - [Ww]) + [Ww]) TTS_ENGINE="swift" NOISEFLOOR="500" TTS_OPTS=$SWIFT_OPTS - ;; + ;; *) TTS_ENGINE=$DEFAULT_TTS TTS_OPTS=$DEFAULT_TTS_OPTS @@ -2287,6 +2287,7 @@ @SIMUL1@ @SIMUL2@ \$(SILENT)\$(MAKE) -C \$(FIRMDIR) OBJDIR=\$(BUILDDIR)/firmware + \$(SILENT)mkdir -p \$(BUILDDIR)/lang \$(SILENT)\$(MAKE) -C \$(APPSDIR) OBJDIR=\$(BUILDDIR)/@APPS@ bin: tools @LANGS@ @@ -2305,11 +2306,12 @@ clean: \$(SILENT)echo Cleaning build directory - \$(SILENT)rm -rf rockbox.zip TAGS @APPS@ firmware comsim sim lang.[ch]\ - manual *.pdf *.a credits.raw @OUTPUT@ bitmaps pluginbitmaps \ - @ARCHOSROM@ @FLASHFILE@ UI256.bmp rockbox-full.zip \ + \$(SILENT)rm -rf rockbox.zip TAGS @APPS@ firmware comsim sim lang \ + lang*.h manual *.pdf *.a credits.raw @OUTPUT@ bitmaps \ + pluginbitmaps @ARCHOSROM@ @FLASHFILE@ UI256.bmp rockbox-full.zip \ html txt rockbox-manual*.zip sysfont.h rockbox-info.txt \ - voicefontids *.wav *.mp3 *.voice max_language_size.h + voicefontids *.wav *.mp3 *.voice max_language_size.h \ + max_plugin_language_size.h tools: \$(SILENT)\$(MAKE) -C \$(TOOLSDIR) CC=\$(HOSTCC) AR=\$(HOSTAR) @TOOLSET@ Index: tools/make.inc =================================================================== --- tools/make.inc (revision 18265) +++ tools/make.inc (working copy) @@ -45,7 +45,7 @@ rm $$del; \ del=""; \ fi \ - done | sed -e "s:[^[:space:]]*lang.h:$(OBJDIR)/lang.o:" \ + done | sed -e "s:[^[:space:]]*lang.h:$(BUILDDIR)/lang/lang_core.o:" \ -e "s:[^[:space:]]*sysfont.h:$(BUILDDIR)/sysfont.h:" \ -e "s:[^[:space:]]*max_language_size.h:$(BUILDDIR)/max_language_size.h:" \ > $(DEPFILE); \ Index: apps/language.c =================================================================== --- apps/language.c (revision 18265) +++ apps/language.c (working copy) @@ -20,9 +20,6 @@ ****************************************************************************/ #include -#if defined(SIMULATOR) && defined(__MINGW32__) -extern int printf(const char *format, ...); -#endif #include "language.h" #include "lang.h" @@ -30,64 +27,91 @@ #include "string.h" static unsigned char language_buffer[MAX_LANGUAGE_SIZE]; +unsigned char** plugin_language_strings; +static void lang_init_helper(unsigned char *builtin, unsigned char **dest, int count) +{ + while(count--) { + *dest++ = builtin; + //DEBUGF("%d %s\n", count, builtin); + builtin += strlen((char *)builtin) + 1; /* advance pointer to next string */ + } +} + void lang_init(void) { - int i; - unsigned char *ptr = (unsigned char *) language_builtin; - - for (i = 0; i < LANG_LAST_INDEX_IN_ARRAY; i++) { - language_strings[i] = ptr; - ptr += strlen((char *)ptr) + 1; /* advance pointer to next string */ - } + lang_init_helper((unsigned char*)core_language_builtin, language_strings, + LANG_LAST_INDEX_IN_ARRAY); } -int lang_load(const char *filename) +int lang_load_helper(const char *filename, const unsigned char *builtin, + unsigned char **dest, unsigned char *buffer, + unsigned int user, unsigned int max) { - int fsize; int fd = open(filename, O_RDONLY); int retcode=0; - unsigned char lang_header[3]; + unsigned int id, num_str, lang_size, foffset; + unsigned char read_buffer[6]; if(fd < 0) return 1; - fsize = filesize(fd) - 2; - if(fsize <= MAX_LANGUAGE_SIZE) { - read(fd, lang_header, 3); - if((lang_header[0] == LANGUAGE_COOKIE) && - (lang_header[1] == LANGUAGE_VERSION) && - (lang_header[2] == TARGET_ID)) { - read(fd, language_buffer, MAX_LANGUAGE_SIZE); - unsigned char *ptr = language_buffer; - int id; - lang_init(); /* initialize with builtin */ + read(fd, read_buffer, 3); + if((read_buffer[0] == LANGUAGE_COOKIE) && + (read_buffer[1] == LANGUAGE_VERSION) && + (read_buffer[2] == TARGET_ID)) { + /* read in the number of strings, filesize, and file offset*/ + lseek(fd, user * 6, SEEK_CUR); + read(fd, read_buffer, 6); + num_str = (read_buffer[0]<<8) | read_buffer[1]; + lang_size = (read_buffer[2]<<8) | read_buffer[3]; + foffset = (read_buffer[4]<<8) | read_buffer[5]; + DEBUGF("%d %d %d\n", num_str, lang_size, foffset); + if(lang_size <= MAX_LANGUAGE_SIZE) { + /* initialize with builtin */ + lang_init_helper((unsigned char*)builtin, dest, num_str); + lseek(fd, foffset, SEEK_SET); + DEBUGF("1: %d %d\n", (buffer[0]<<8) | buffer[1], max); + read(fd, buffer, lang_size); + DEBUGF("2: %d %d\n", (buffer[0]<<8) | buffer[1], max); - while(fsize>3) { - id = (ptr[0]<<8) | ptr[1]; /* get two-byte id */ - ptr+=2; /* pass the id */ - if(id < LANG_LAST_INDEX_IN_ARRAY) { + while(lang_size > 3 && lang_size < 1000000) { + id = (buffer[0]<<8) | buffer[1]; /* get two-byte id */ + buffer += 2; /* pass the id */ + if(id < max) { #if 0 - printf("%2x New: %30s ", id, ptr); - printf("Replaces: %s\n", language_strings[id]); + DEBUGF("%2x New: %30s ", id, buffer); + DEBUGF("Replaces: %s\n", dest[id]); #endif - language_strings[id] = ptr; /* point to this string */ + /* point to the string if it should loaded */ + dest[id] = buffer; } - while(*ptr) { /* pass the string */ - fsize--; - ptr++; + while(*buffer) { /* pass the string */ + lang_size--; + buffer++; } - fsize-=3; /* the id and the terminating zero */ - ptr++; /* pass the terminating zero-byte */ + lang_size-=3; /* the id and the terminating zero */ + buffer++; /* pass the terminating zero-byte */ } } else { - DEBUGF("Illegal language file\n"); - retcode = 2; + DEBUGF("Language %s too large: %d\n", filename, lang_size); + retcode = 3; } } else { - DEBUGF("Language %s too large: %d\n", filename, fsize); - retcode = 3; + DEBUGF("Illegal language file\n"); + retcode = 2; } close(fd); return retcode; } + +int lang_load(const char *filename) +{ + return lang_load_helper(filename, core_language_builtin, language_strings, + language_buffer, 0, LANG_LAST_INDEX_IN_ARRAY); +} + +void lang_set_plugin_strings(unsigned char** strings_ptr) +{ + plugin_language_strings = strings_ptr; +} Index: apps/language.h =================================================================== --- apps/language.h (revision 18265) +++ apps/language.h (working copy) @@ -28,12 +28,17 @@ /* both these must match the two initial bytes in the binary lang file */ #define LANGUAGE_COOKIE 0x1a -#define LANGUAGE_VERSION 0x04 +#define LANGUAGE_VERSION 0x05 /* Initialize language array with the builtin strings */ void lang_init(void); /* load a given language file */ int lang_load(const char *filename); +int lang_load_helper(const char *filename, const unsigned char *builtin, + unsigned char **dest, unsigned char *buffer, + unsigned int user, unsigned int max); + +void lang_set_plugin_strings(unsigned char** strings_ptr); #endif Index: apps/Makefile =================================================================== --- apps/Makefile (revision 18265) +++ apps/Makefile (working copy) @@ -66,7 +66,7 @@ -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} \ -DTARGET_NAME=\"$(MODELNAME)\" -OBJS2 := $(OBJDIR)/lang.o $(patsubst %.c, $(OBJDIR)/%.o, $(SRC)) +OBJS2 := $(patsubst %.c, $(OBJDIR)/%.o, $(SRC)) $(BUILDDIR)/lang/lang_core.o OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2)) SOURCES = $(SRC) LINKFILE = $(OBJDIR)/linkage.lds @@ -223,15 +223,18 @@ for f in `cat $(OBJDIR)/features`; do feat="$$feat:$$f" ; done ; \ echo "$$feat" >$(OBJDIR)/genlang-features -$(OBJDIR)/lang.o: lang/$(LANGUAGE).lang $(OBJDIR)/features +$(BUILDDIR)/lang/lang_core.o: lang/$(LANGUAGE).lang $(OBJDIR)/features $(SILENT)for f in `cat $(OBJDIR)/features`; do feat="$$feat:$$f" ; done; \ perl -s $(TOOLSDIR)/genlang -p=$(BUILDDIR)/lang -t=$(MODELNAME)$$feat $< - $(call PRINTS,CC lang.c)$(CC) $(CFLAGS) -c $(BUILDDIR)/lang.c -o $@ + $(call PRINTS,CC lang_core.c)$(CC) $(CFLAGS) -c $(BUILDDIR)/lang/lang_core.c -o $(BUILDDIR)/lang/lang_core.o + $(call PRINTS,CC lang_blackjack.c)$(CC) $(CFLAGS) -c $(BUILDDIR)/lang/lang_blackjack.c -o $(BUILDDIR)/lang/lang_blackjack.o + $(call PRINTS,CC lang_chessbox.c)$(CC) $(CFLAGS) -c $(BUILDDIR)/lang/lang_chessbox.c -o $(BUILDDIR)/lang/lang_chessbox.o + $(call PRINTS,CC lang_chopper.c)$(CC) $(CFLAGS) -c $(BUILDDIR)/lang/lang_chopper.c -o $(BUILDDIR)/lang/lang_chopper.o clean: $(call PRINTS,cleaning apps)-rm -f $(OBJS) $(BUILDDIR)/$(BINARY) $(OBJDIR)/rockbox.asm \ $(OBJDIR)/rockbox.bin $(OBJDIR)/rockbox.elf $(OBJDIR)/*.map \ - $(OBJDIR)/lang.o $(OBJDIR)/build.lang $(BUILDDIR)/lang.[ch] \ + $(BUILDDIR)/lang/lang_*.o $(OBJDIR)/build.lang $(BUILDDIR)/lang*.[ch] \ $(LINKFILE) $(BUILDDIR)/rockbox.ucl $(LINKROM) \ $(BUILDDIR)/rombox.ucl $(OBJDIR)/rombox.bin $(OBJDIR)/rombox.elf \ $(MAXOUTFILE) $(DEPFILE) Index: apps/plugins/Makefile =================================================================== --- apps/plugins/Makefile (revision 18265) +++ apps/plugins/Makefile (working copy) @@ -116,7 +116,7 @@ # This is the SDL simulator version $(OBJDIR)/%.rock : $(OBJDIR)/%.o $(BUILDDIR)/libplugin.a $(BITMAPLIBS) - $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $< -L$(BUILDDIR) $(CODECLIBS) -lplugin $(LINKBITMAPS) -o $@ + $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $< -L$(BUILDDIR) $(CODECLIBS) -lplugin $(LINKBITMAPS) $(BUILDDIR)/lang/lang_*.o -o $@ ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) # 'x' must be kept or you'll have "Win32 error 5" # $ fgrep 5 /usr/include/w32api/winerror.h | head -1 Index: apps/plugins/chessbox/chessbox.c =================================================================== --- apps/plugins/chessbox/chessbox.c (revision 18265) +++ apps/plugins/chessbox/chessbox.c (working copy) @@ -22,6 +22,7 @@ ****************************************************************************/ #include "plugin.h" +#include "pluginlib_lang.h" #ifdef HAVE_LCD_BITMAP @@ -580,7 +581,7 @@ } } while (!exit_game && !exit_viewer); } else { - rb->splash ( 200 , "Error parsing game !"); + rb->splash ( 200 , str(P_LANG_CHESSBOX_PARSE_ERROR)); } } while (!exit_viewer); } @@ -593,7 +594,11 @@ bool menu_quit = false; MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"New Game","Resume Game", - "Save Game", "Restore Game", "Quit"); + "Save Game", "Restore Game", "Quit"); + /*MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL, + ID2P(LANG_CHESSBOX_MENU_RESTART_GAME), + ID2P(LANG_CHESSBOX_MENU_SELECT_OTHER_GAME), + ID2P(LANG_CHESSBOX_MENU_QUIT));*/ while(!menu_quit) { @@ -781,7 +786,7 @@ while (!exit) { if ( mate ) { - rb->splash ( 500 , "Checkmate!" ); + rb->splash ( 500 , str(P_LANG_CHESSBOX_CHECKMATE) ); rb->button_get(true); pgn_store_game(rb, game); GNUChess_Initialize(); @@ -792,7 +797,7 @@ switch (command.type) { case COMMAND_MOVE: if ( ! VerifyMove (opponent, command.mv_s , 0 , &command.mv, move_buffer ) ) { - rb->splash ( 50 , "Illegal move!" ); + rb->splash ( 50 , str(P_LANG_CHESSBOX_ILLEGAL_MOVE) ); cb_drawboard(); } else { cb_drawboard(); @@ -912,6 +917,7 @@ #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif + plugin_use_lang(rb, USER_CHESSBOX, chessbox_language_builtin); /* end of plugin init */ Index: apps/plugins/chessbox/Makefile =================================================================== --- apps/plugins/chessbox/Makefile (revision 18265) +++ apps/plugins/chessbox/Makefile (working copy) @@ -9,7 +9,7 @@ INCLUDES = -I$(APPSDIR) -I.. -I. $(TARGET_INC) -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ -I$(BUILDDIR)/pluginbitmaps -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) \ - -I$(BUILDDIR) + -I$(BUILDDIR) -I$(APPSDIR)/plugins/lib CFLAGS = $(INCLUDES) $(GCCOPTS) -O2 $(TARGET) $(EXTRA_DEFINES) \ -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN @@ -40,7 +40,7 @@ all: $(OUTPUT) ifndef SIMVER -$(OBJDIR)/chessbox.elf: $(OBJS) $(LINKFILE) $(BITMAPLIBS) +$(OBJDIR)/chessbox.elf: $(BUILDDIR)/libplugin.a $(OBJS) $(LINKFILE) $(BITMAPLIBS) $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \ $(LINKBITMAPS) -T$(LINKFILE) -Wl,--gc-sections -Wl,-Map,$(OBJDIR)/chessbox.map @@ -67,8 +67,8 @@ ################################################### # This is the SDL simulator version -$(OUTPUT): $(OBJS) - $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -o $@ +$(OUTPUT): $(BUILDDIR)/libplugin.a $(OBJS) + $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) $(BUILDDIR)/lang/lang_chessbox.o -o $@ ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) # 'x' must be kept or you'll have "Win32 error 5" # $ fgrep 5 /usr/include/w32api/winerror.h | head -1 Index: apps/plugins/lib/pluginlib_lang.c =================================================================== --- apps/plugins/lib/pluginlib_lang.c (revision 0) +++ apps/plugins/lib/pluginlib_lang.c (revision 0) @@ -0,0 +1,53 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Tom Ross + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" +#include "pluginlib_lang.h" + +static unsigned char *plugin_language_buffer; + +void plugin_use_lang(const struct plugin_api* rb, enum user_type user, + const unsigned char* plugin_language_builtin) +{ + char buf[64]; + char* p_lang = "english"; /* default */ + size_t buffer_size; + size_t langsize = 9000; + /* TODO: calculate the proper language size */ + //size_t langsize = sizeof(char*) * (P_LANG_LAST_INDEX_IN_ARRAY - LANG_LAST_INDEX_IN_ARRAY); + unsigned char **plugin_language_strings; + + if(langsize & 3) + langsize += (4 - (langsize & 3)); + + plugin_language_buffer = (unsigned char*)rb->plugin_get_buffer(&buffer_size); + plugin_language_strings = (unsigned char **)(plugin_language_buffer + + langsize); + rb->lang_set_plugin_strings(plugin_language_strings); + if (rb->global_settings->lang_file[0] && + rb->global_settings->lang_file[0] != 0xff) { + /* try to open the lang file of the selected language */ + p_lang = (char *)rb->global_settings->lang_file; + } + snprintf(buf, sizeof(buf), LANG_DIR "/%s.lng", p_lang); + /* TODO: we should pass the first id of a plugin language to save on memory */ + /* TODO: pass buffer_size-lang_size as the maximum size of a plugin lang */ + rb->lang_load_helper(buf, plugin_language_builtin, plugin_language_strings, + plugin_language_buffer, user, P_LANG_LAST_INDEX_IN_ARRAY); +} Index: apps/plugins/lib/pluginlib_lang.h =================================================================== --- apps/plugins/lib/pluginlib_lang.h (revision 0) +++ apps/plugins/lib/pluginlib_lang.h (revision 0) @@ -0,0 +1,32 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Tom Ross + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef _LIB_LANG_H_ +#define _LIB_LANG_H_ + +#include "plugin.h" +#include "lang.h" +#include "lang_plugin.h" + +#undef str +#define str(x) ((x < LANG_LAST_INDEX_IN_ARRAY) ? rb->language_strings[x] : \ + (*rb->plugin_language_strings)[x - LANG_LAST_INDEX_IN_ARRAY - 1]) + +void plugin_use_lang(const struct plugin_api* rb, enum user_type user, + const unsigned char* plugin_language_builtin); +#endif /* _LIB_LANG_H_ */ Index: apps/plugins/lib/SOURCES =================================================================== --- apps/plugins/lib/SOURCES (revision 18265) +++ apps/plugins/lib/SOURCES (working copy) @@ -39,6 +39,7 @@ #endif pluginlib_actions.c helper.c +pluginlib_lang.c #ifdef HAVE_TOUCHPAD touchscreen.c #endif Index: apps/plugins/chopper.c =================================================================== --- apps/plugins/chopper.c (revision 18265) +++ apps/plugins/chopper.c (working copy) @@ -21,6 +21,7 @@ ****************************************************************************/ #include "plugin.h" +#include "pluginlib_lang.h" #include "xlcd.h" #include "configfile.h" #include "helper.h" @@ -44,7 +45,6 @@ #define QUIT BUTTON_OFF #define ACTION BUTTON_UP #define ACTION2 BUTTON_SELECT -#define ACTIONTEXT "SELECT" #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ @@ -52,58 +52,48 @@ #define QUIT BUTTON_MENU #define ACTION BUTTON_SELECT -#define ACTIONTEXT "SELECT" #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD /* grayscale at the moment */ #define QUIT BUTTON_POWER #define ACTION BUTTON_UP #define ACTION2 BUTTON_SELECT -#define ACTIONTEXT "SELECT" #elif CONFIG_KEYPAD == IRIVER_H10_PAD #define QUIT BUTTON_POWER #define ACTION BUTTON_RIGHT -#define ACTIONTEXT "RIGHT" #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ (CONFIG_KEYPAD == SANSA_C200_PAD) #define QUIT BUTTON_POWER #define ACTION BUTTON_SELECT -#define ACTIONTEXT "SELECT" #elif CONFIG_KEYPAD == GIGABEAT_PAD #define QUIT BUTTON_MENU #define ACTION BUTTON_SELECT -#define ACTIONTEXT "SELECT" #elif CONFIG_KEYPAD == RECORDER_PAD #define QUIT BUTTON_OFF #define ACTION BUTTON_PLAY -#define ACTIONTEXT "PLAY" #elif CONFIG_KEYPAD == ONDIO_PAD #define QUIT BUTTON_OFF #define ACTION BUTTON_UP #define ACTION2 BUTTON_MENU -#define ACTIONTEXT "UP" #elif CONFIG_KEYPAD == GIGABEAT_S_PAD #define QUIT BUTTON_BACK #define ACTION BUTTON_SELECT #define ACTION2 BUTTON_MENU -#define ACTIONTEXT "SELECT" #elif CONFIG_KEYPAD == MROBE100_PAD #define QUIT BUTTON_POWER #define ACTION BUTTON_SELECT -#define ACTIONTEXT "SELECT" #elif CONFIG_KEYPAD == IAUDIO_M3_PAD #define QUIT BUTTON_RC_REC #define ACTION BUTTON_RC_PLAY #define ACTION2 BUTTON_RC_MODE -#define ACTIONTEXT "PLAY" #elif CONFIG_KEYPAD == COWOND2_PAD #define QUIT BUTTON_POWER @@ -122,10 +112,7 @@ #ifndef ACTION2 #define ACTION2 BUTTON_BOTTOMRIGHT #endif -#ifndef ACTIONTEXT -#define ACTIONTEXT "BOTTOMRIGHT" #endif -#endif static const struct plugin_api* rb; @@ -529,17 +516,19 @@ #if LCD_DEPTH >= 2 rb->lcd_set_foreground(LCD_LIGHTGRAY); #endif - rb->splash(HZ, "Game Over"); + //rb->splash(HZ, "Game Over"); + rb->splash(HZ, str(P_LANG_GAMEOVER)); if (score > highscore) { char scoretext[30]; highscore = score; - rb->snprintf(scoretext, sizeof(scoretext), "New High Score: %d", - highscore); + rb->snprintf(scoretext, sizeof(scoretext), "%s: %d", + str(P_LANG_HIGHSCORE), highscore); rb->splash(HZ*2, scoretext); } - rb->splash(HZ/4, "Press " ACTIONTEXT " to continue"); + //rb->splash(HZ/4, "Press " ACTIONTEXT " to continue"); + rb->splash(HZ/4, str(P_LANG_CHOPPER_CONTINUE)); rb->lcd_update(); rb->lcd_set_drawmode(DRMODE_SOLID); @@ -649,21 +638,24 @@ rb->lcd_set_foreground(LCD_WHITE); #endif -#if LCD_WIDTH <= 128 +/*#if LCD_WIDTH <= 128 rb->snprintf(s, sizeof(s), "Dist: %d", score); #else rb->snprintf(s, sizeof(s), "Distance: %d", score); -#endif +#endif*/ + rb->snprintf(s, sizeof(s), "%s: %d", str(P_LANG_CHOPPER_DISTANCE), score); rb->lcd_getstringsize(s, &w, NULL); rb->lcd_putsxy(2, 2, s); if (score < highscore) { int w2; -#if LCD_WIDTH <= 128 +/*#if LCD_WIDTH <= 128 rb->snprintf(s, sizeof(s), "Hi: %d", highscore); #else rb->snprintf(s, sizeof(s), "Best: %d", highscore); -#endif +#endif*/ + rb->snprintf(s, sizeof(s), "%s: %d", str(P_LANG_CHOPPER_BESTSCORE), + highscore); rb->lcd_getstringsize(s, &w2, NULL); if (LCD_WIDTH - 2 - w2 > w + 2) rb->lcd_putsxy(LCD_WIDTH - 2 - w2, 2, s); @@ -686,6 +678,9 @@ MENUITEM_STRINGLIST(menu,"Chopper Menu",NULL,"Start New Game","Resume Game", "Level","Quit"); + //MENUITEM_STRINGLIST(menu, ID2P(P_LANG_CHOPPER_MENUTITLE), NULL, + // ID2P(P_LANG_CHOPPER_START),"Resume Game", + // ID2P(P_LANG_CHOPPER_LEVEL),"Quit"); #ifdef HAVE_LCD_COLOR rb->lcd_set_foreground(LCD_WHITE); @@ -710,11 +705,11 @@ menu_quit=true; res = -1; } else if(menunum==0){ - rb->splash(HZ, "No game to resume"); + rb->splash(HZ, str(P_LANG_CHOPPER_NO_GAME)); } break; case 2: - rb->set_option("Level", &iLevelMode, INT, levels, 2, NULL); + rb->set_option(str(P_LANG_CHOPPER_LEVEL), &iLevelMode, INT, levels, 2, NULL); break; case 3: menu_quit=true; @@ -987,6 +982,7 @@ rb = api; int ret; + plugin_use_lang(rb, USER_CHOPPER, chopper_language_builtin); rb->lcd_setfont(FONT_SYSFIXED); #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); Index: apps/plugins/blackjack.c =================================================================== --- apps/plugins/blackjack.c (revision 18265) +++ apps/plugins/blackjack.c (working copy) @@ -5,7 +5,7 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ - * $Id: $ + * $Id$ * * Copyright (C) 2006 Tom Ross * @@ -20,6 +20,8 @@ ****************************************************************************/ #include "plugin.h" +#include "pluginlib_lang.h" +#include "plugin_talk.h" #include "card_deck.h" #include "card_back.h" @@ -383,32 +385,34 @@ ******************************************************************************/ static void blackjack_drawtable(struct game_context* bj) { unsigned int w, h, y_loc; - char str[10]; + char str[64]; #if LCD_HEIGHT <= 64 - rb->lcd_getstringsize("Bet", &w, &h); - rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet"); + rb->snprintf(str, sizeof(str), "%s", str(P_LANG_BET)); + rb->lcd_getstringsize(str, &w, &h); + rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, str); rb->snprintf(str, 9, "$%d", bj->current_bet); rb->lcd_getstringsize(str, &w, &h); rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str); y_loc = LCD_HEIGHT/2; #else - rb->lcd_getstringsize("Bet", &w, &h); - rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet"); + rb->snprintf(str, sizeof(str), "%s", str(P_LANG_BET)); + rb->lcd_getstringsize(str, &w, &h); + rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, str); rb->snprintf(str, 9, "$%d", bj->current_bet); rb->lcd_getstringsize(str, &w, &h); rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str); rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2); y_loc = LCD_HEIGHT/2 + h; #endif - - rb->lcd_putsxy(0,0, "Dealer"); - rb->lcd_getstringsize("Player", &w, &h); - rb->lcd_putsxy(0, y_loc, "Player"); - rb->lcd_getstringsize("Total", &w, &h); - rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total"); - rb->lcd_getstringsize("Money", &w, &h); - rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money"); + rb->lcd_putsxy(0, 0, str(P_LANG_DEALER)); + rb->lcd_putsxy(0, y_loc, str(P_LANG_PLAYER)); + rb->snprintf(str, sizeof(str), "%s", str(P_LANG_TOTAL)); + rb->lcd_getstringsize(str, &w, &h); + rb->lcd_putsxy(LCD_WIDTH - w, y_loc, str); + rb->snprintf(str, sizeof(str), "%s", str(P_LANG_MONEY)); + rb->lcd_getstringsize(str, &w, &h); + rb->lcd_putsxy(LCD_WIDTH - w, 0, str); rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet); rb->lcd_getstringsize(str, &w, &h); rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str); @@ -486,21 +490,24 @@ * initial cards. ******************************************************************************/ static void deal_init_cards(struct game_context* bj) { + bj->dealer_cards[0] = new_card(); + rb->talk_number(bj->dealer_cards[0].value, true); bj->dealer_total += bj->dealer_cards[0].value; + draw_card(bj->dealer_cards[0], true, dealer_x, dealer_y); - draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y); - bj->dealer_cards[1] = new_card(); bj->dealer_total += bj->dealer_cards[1].value; - draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y); + draw_card(bj->dealer_cards[1], false, dealer_x + CARD_WIDTH + 4, dealer_y); bj->player_cards[0][0] = new_card(); + rb->talk_number(bj->player_cards[0][0].value, true); bj->player_total += bj->player_cards[0][0].value; draw_card(bj->player_cards[0][0], true, player_x, player_y); player_x += CARD_WIDTH + 4; bj->player_cards[0][1] = new_card(); + rb->talk_number(bj->player_cards[0][1].value, true); bj->player_total += bj->player_cards[0][1].value; draw_card(bj->player_cards[0][1], true, player_x, player_y); player_x += CARD_WIDTH + 4; @@ -610,12 +617,15 @@ ******************************************************************************/ static void finish_dealer(struct game_context* bj) { signed int temp = 0; + + rb->talk_number(bj->dealer_cards[1].value, true); if (bj->dealer_total > 16 && bj->dealer_total < 22) return; while (bj->dealer_total < 17) { bj->dealer_cards[bj->num_dealer_cards] = new_card(); + rb->talk_number(bj->dealer_cards[bj->num_dealer_cards].value, true); bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value; bj->num_dealer_cards++; } @@ -636,32 +646,41 @@ ******************************************************************************/ static void finish_game(struct game_context* bj) { unsigned int rValue, w, h; - char str[19]; + char str[64]; do { finish_dealer(bj); } while (bj->dealer_total < 17); + rb->talk_id(P_LANG_DEALER, true); + rb->talk_number(bj->dealer_total, true); + rb->talk_id(P_LANG_PLAYER, true); + rb->talk_number(bj->player_total, true); redraw_board(bj); rValue = check_totals(bj); if (rValue == 0) { - rb->snprintf(str, sizeof(str), " Bust! "); + rb->snprintf(str, sizeof(str), " %s ", str(P_LANG_BUST)); + rb->talk_id(P_LANG_BUST, true); bj->player_money -= bj->current_bet; } else if (rValue == 1) { - rb->snprintf(str, sizeof(str), " Sorry, you lost. "); + rb->snprintf(str, sizeof(str), " %s ", str(P_LANG_LOST)); + rb->talk_id(P_LANG_LOST, true); bj->player_money -= bj->current_bet; } else if (rValue == 2) { - rb->snprintf(str, sizeof(str), " Push "); + rb->snprintf(str, sizeof(str), " %s ", str(P_LANG_PUSH)); + rb->talk_id(P_LANG_PUSH, true); } else if (rValue == 3) { - rb->snprintf(str, sizeof(str), " You won! "); + rb->snprintf(str, sizeof(str), " %s ", str(P_LANG_WON)); + rb->talk_id(P_LANG_WON, true); bj->player_money+= bj->current_bet; } else { - rb->snprintf(str, sizeof(str), " Blackjack! "); + rb->snprintf(str, sizeof(str), " %s! ", str(P_LANG_BLACKJACK)); + rb->talk_id(P_LANG_BLACKJACK, true); bj->player_money += bj->current_bet * 3 / 2; } rb->lcd_getstringsize(str, &w, &h); @@ -671,7 +690,7 @@ rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2); rb->lcd_set_drawmode(DRMODE_SOLID); rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str); - rb->snprintf(str, 12, "You have %d", bj->player_total); + rb->snprintf(str, sizeof(str), str(P_LANG_YOU_HAVE), bj->player_total); rb->lcd_getstringsize(str, &w, &h); rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str); #else @@ -818,7 +837,7 @@ static void blackjack_callback(void* param) { struct game_context* bj = (struct game_context*) param; if(bj->dirty) { - rb->splash(HZ, "Saving high scores..."); + rb->splash(HZ, ID2P(P_LANG_SAVING_HIGH_SCORES)); blackjack_savescores(bj); } } @@ -826,40 +845,41 @@ /***************************************************************************** * blackjack_get_yes_no() gets a yes/no answer from the user ******************************************************************************/ -static unsigned int blackjack_get_yes_no(char message[20]) { +static unsigned int blackjack_get_yes_no(const char *message) { int button; - unsigned int w, h, b, choice = 0; + unsigned int w1, w2, h, b, choice = 0; bool breakout = false; - char message_yes[24], message_no[24]; + char message_yes[64], message_no[64]; + const char *stg[] = {message_yes, message_no}; - rb->strcpy(message_yes, message); - rb->strcpy(message_no, message); - rb->strcat(message_yes, " Yes"); - rb->strcat(message_no, " No"); - rb->lcd_getstringsize(message_yes, &w, &h); - const char *stg[] = {message_yes, message_no}; - + rb->snprintf(message_yes, sizeof(message_yes), "%s %s", message, str(LANG_SET_BOOL_YES)); + rb->snprintf(message_no, sizeof(message_no), "%s %s", message, str(LANG_SET_BOOL_NO)); + rb->lcd_getstringsize(message_yes, &w1, &h); + rb->lcd_getstringsize(message_no, &w2, &h); + w1 = MAX(w1, w2); + rb->talk_id(LANG_SET_BOOL_YES, true); + #if LCD_HEIGHT <= 64 b = 2*h+1; #else b = h-1; #endif + + while(!breakout) { #ifdef HAVE_LCD_COLOR - rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3); - rb->lcd_set_foreground(LCD_BLACK); - rb->lcd_set_background(LCD_WHITE); + rb->lcd_fillrect(LCD_WIDTH/2 - w1/2, LCD_HEIGHT/2 + b, w1+1, h+3); + rb->lcd_set_foreground(LCD_BLACK); + rb->lcd_set_background(LCD_WHITE); #else - rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID); - rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3); - rb->lcd_set_drawmode(DRMODE_SOLID); + rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID); + rb->lcd_fillrect(LCD_WIDTH/2 - w1/2, LCD_HEIGHT/2 + b, w1+1, h+3); + rb->lcd_set_drawmode(DRMODE_SOLID); #endif - rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4); - - while(!breakout) { - rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]); - rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1, - w+3, h+4); + rb->lcd_drawrect(LCD_WIDTH/2 - w1/2 - 1, LCD_HEIGHT/2 + b - 1, w1+3, h+4); + rb->lcd_putsxy(LCD_WIDTH/2 - w1/2, LCD_HEIGHT/2 + b +1, stg[choice]); + rb->lcd_update_rect(LCD_WIDTH/2 - w1/2 - 1, LCD_HEIGHT/2 + b -1, + w1+3, h+4); button = rb->button_get(true); switch(button) { @@ -868,6 +888,7 @@ case BJACK_RIGHT: case (BJACK_RIGHT|BUTTON_REPEAT): choice ^= 1; + rb->talk_id(choice ? LANG_SET_BOOL_NO : LANG_SET_BOOL_YES, true); break; case BJACK_START: breakout = true; break; @@ -875,28 +896,27 @@ choice = BJ_QUIT; break; } +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(FG_COLOR); + rb->lcd_set_background(BG_COLOR); +#endif } -#if LCD_DEPTH > 1 - rb->lcd_set_foreground(FG_COLOR); - rb->lcd_set_background(BG_COLOR); -#endif return choice; } /***************************************************************************** * blackjack_get_amount() gets an amount from the player to be used ******************************************************************************/ -static signed int blackjack_get_amount(char message[20], signed int lower_limit, - signed int upper_limit, - signed int start) { +static signed int blackjack_get_amount(const char *message, signed int lower_limit, + signed int upper_limit, signed int start) { int button; char str[6]; bool changed = false; unsigned int w, h; signed int amount; - rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */ + rb->lcd_getstringsize(message, &w, &h); if (start > upper_limit) amount = upper_limit; @@ -915,42 +935,29 @@ rb->lcd_puts(0, 1, message); rb->snprintf(str, 9, "$%d", amount); rb->lcd_puts(0, 2, str); - rb->lcd_puts(0, 3, "RIGHT: +1"); - rb->lcd_puts(0, 4, "LEFT: -1"); - rb->lcd_puts(0, 5, "UP: +10"); - rb->lcd_puts(0, 6, "DOWN: -10"); + rb->lcd_puts(0, 3, str(P_LANG_BET_INC_SMALL)); + rb->lcd_puts(0, 4, str(P_LANG_BET_DEC_SMALL)); + rb->lcd_puts(0, 5, str(P_LANG_BET_INC_BIG)); + rb->lcd_puts(0, 6, str(P_LANG_BET_DEC_BIG)); rb->lcd_update(); #else rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID); - rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2, + rb->lcd_fillrect(LCD_WIDTH/2 - w / 2 - 1, LCD_HEIGHT/2 - 4*h - 3, w+3, 8*h -3); rb->lcd_set_drawmode(DRMODE_SOLID); - rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2, + rb->lcd_drawrect(LCD_WIDTH/2 - w / 2 - 1, LCD_HEIGHT/2 - 4*h - 3, w+3, 8*h -3); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message); + rb->lcd_putsxy(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 - 4*h - 1, message); rb->snprintf(str, 9, "$%d", amount); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str); -#if (CONFIG_KEYPAD == IPOD_4G_PAD) || \ - (CONFIG_KEYPAD == IPOD_3G_PAD) || \ - (CONFIG_KEYPAD == IPOD_1G2G_PAD) - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10"); -#elif CONFIG_KEYPAD == IRIVER_H10_PAD - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10"); -#else - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10"); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10"); + rb->talk_number(amount, true); + rb->lcd_putsxy(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 - 3*h, str); + rb->lcd_putsxy(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 - h-2, str(P_LANG_BET_INC_SMALL)); + rb->lcd_putsxy(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 - 1, str(P_LANG_BET_DEC_SMALL)); + rb->lcd_putsxy(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 + h, str(P_LANG_BET_INC_BIG)); + rb->lcd_putsxy(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 + 2*h + 1, str(P_LANG_BET_DEC_BIG)); + rb->lcd_update_rect(LCD_WIDTH/2 - w / 2 - 2, LCD_HEIGHT/2 - 9*h/2, w+2, 8*h-2); + rb->lcd_update(); #endif - rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 2, LCD_HEIGHT/2 - 9*h/2, 37*w/2 + 1, - 8*h-2); -#endif while(true) { button = rb->button_get(true); @@ -1005,15 +1012,16 @@ if(changed) { rb->snprintf(str, 9, "$%d", amount); + rb->talk_number(amount, false); #if LCD_HEIGHT <= 64 rb->lcd_puts(0, 2, str); rb->lcd_update(); #else rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID); - rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h); + rb->lcd_fillrect(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 - 3*h, w, h); rb->lcd_set_drawmode(DRMODE_SOLID); - rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str); - rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h); + rb->lcd_putsxy(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 - 3*h, str); + rb->lcd_update_rect(LCD_WIDTH/2 - w / 2, LCD_HEIGHT/2 - 3*h, w, h); #endif changed = false; } @@ -1024,7 +1032,8 @@ * blackjack_get_bet() gets the player's bet. ******************************************************************************/ static void blackjack_get_bet(struct game_context* bj) { - bj->current_bet = blackjack_get_amount("Please enter a bet", 10, + rb->talk_id(P_LANG_GET_BET, true); + bj->current_bet = blackjack_get_amount(str(P_LANG_GET_BET), 10, bj->player_money, bj->current_bet); } @@ -1044,7 +1053,8 @@ * means a split has already occurred and the first hand is done. ******************************************************************************/ static void split(struct game_context* bj) { - if (blackjack_get_yes_no("Split?") == 1) + rb->talk_id(P_LANG_ASK_SPLIT, true); + if (blackjack_get_yes_no(str(P_LANG_ASK_SPLIT)) == 1) bj->split_status = 1; else { bj->split_status = 2; @@ -1062,13 +1072,15 @@ static unsigned int insurance(struct game_context* bj) { unsigned int insurance, max_amount; - insurance = blackjack_get_yes_no("Buy Insurance?"); + rb->talk_id(P_LANG_BUY_INSURANCE, false); + insurance = blackjack_get_yes_no(str(P_LANG_BUY_INSURANCE)); bj->asked_insurance = true; max_amount = bj->current_bet < (unsigned int)bj->player_money ? bj->current_bet/2 : (unsigned int)bj->player_money; if (insurance == 1) return 0; - insurance = blackjack_get_amount("How much?", 0, max_amount, 0); + rb->talk_id(P_LANG_HOW_MUCH, true); + insurance = blackjack_get_amount(str(P_LANG_HOW_MUCH), 0, max_amount, 0); redraw_board(bj); return insurance; } @@ -1077,7 +1089,8 @@ * play_again() checks to see if the player wants to keep playing. ******************************************************************************/ static unsigned int play_again(void) { - return blackjack_get_yes_no("Play Again?"); + rb->talk_id(P_LANG_PLAY_AGAIN, true); + return blackjack_get_yes_no(str(P_LANG_PLAY_AGAIN)); } /***************************************************************************** @@ -1085,8 +1098,7 @@ ******************************************************************************/ static unsigned int blackjack_menu(struct game_context* bj) { int button; - char *title = "Blackjack"; - char str[18]; + char str[64]; unsigned int i, w, h; bool breakout = false; bool showscores = false; @@ -1100,8 +1112,9 @@ if(!showscores) { /* welcome screen to display key bindings */ - rb->lcd_getstringsize(title, &w, &h); - rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, title); + rb->snprintf(str, sizeof(str), "%s", str(P_LANG_BLACKJACK)); + rb->lcd_getstringsize(str, &w, &h); + rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str); #if CONFIG_KEYPAD == RECORDER_PAD rb->lcd_puts(0, 1, "ON: start"); @@ -1244,13 +1257,14 @@ rb->lcd_puts(0, 4, "LCD BOTTOMRIGHT to save/resume"); #endif } else { - rb->snprintf(str, 12, "%s", "High Scores"); + rb->snprintf(str, sizeof(str), "%s", str(P_LANG_HIGH_SCORE_TITLE)); rb->lcd_getstringsize(str, &w, &h); rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str); + rb->talk_id(P_LANG_HIGH_SCORE_TITLE, false); /* print high scores */ for(i=0; isnprintf(str, 14, "#%02d: $%d", i+1, bj->highscores[i]); + rb->snprintf(str, sizeof(str), "#%02d: $%d", i+1, bj->highscores[i]); rb->lcd_puts(0, i+1, str); } } @@ -1274,9 +1288,9 @@ case BJACK_RESUME:/* resume game */ if(!blackjack_loadgame(bj)) { - rb->splash(HZ*2, "Nothing to resume"); + rb->splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME)); } else { - rb->splash(HZ*2, "Loading..."); + rb->splash(HZ*2, ID2P(LANG_WAIT)); breakout = true; } break; @@ -1305,6 +1319,7 @@ int button; unsigned int w, h, temp_var, done = 0, todo = 1; signed int temp; + char buf[64]; bool breakout = false; bool dbl_down = false; @@ -1368,7 +1383,7 @@ !bj->asked_insurance) { temp_var = insurance(bj); if (bj->dealer_total == 21) { - rb->splash(HZ, "Dealer has blackjack"); + rb->splash(HZ, ID2P(P_LANG_DEALER_BLACKJACK)); bj->player_money += temp_var; bj->end_hand = true; breakout = true; @@ -1376,7 +1391,7 @@ finish_game(bj); } else { - rb->splash(HZ, "Dealer does not have blackjack"); + rb->splash(HZ, ID2P(P_LANG_DEALER_NO_BLACKJACK)); bj->player_money -= temp_var; breakout = true; redraw_board(bj); @@ -1401,6 +1416,7 @@ case BJACK_HIT: NEXT_CARD = new_card(); bj->player_total += NEXT_CARD.value; + rb->talk_number(NEXT_CARD.value, true); draw_card(NEXT_CARD, true, player_x, player_y); bj->num_player_cards[done]++; if (bj->num_player_cards[done] == MAX_CARDS + 1) { @@ -1435,13 +1451,13 @@ } } else if((signed int)bj->current_bet * 2 > bj->player_money) { - rb->splash(HZ, "Not enough money to double down."); + rb->splash(HZ, ID2P(P_LANG_NEED_MONEY_DOUBLE_DOWN)); redraw_board(bj); rb->lcd_update(); } break; case BJACK_RESUME: /* save and end game */ - rb->splash(HZ, "Saving game..."); + rb->splash(HZ, ID2P(P_LANG_SAVING_GAME)); blackjack_savegame(bj); /* fall through to BJACK_QUIT */ @@ -1473,20 +1489,22 @@ bj->player_total = temp_var; temp_var = temp; finish_game(bj); - rb->lcd_getstringsize(" Split 1 ", &w, &h); - rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2, - " Split 1 "); - rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2, - w,h); + rb->snprintf(buf, sizeof(buf), " %s 1 ", str(P_LANG_SPLIT)); + rb->talk_id(P_LANG_SPLIT, true); + rb->talk_number(1, true); + rb->lcd_getstringsize(buf, &w, &h); + rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2, buf); bj->current_bet /= 2; rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2, w,h); rb->sleep(HZ*2); bj->player_total = temp_var; finish_game(bj); - rb->lcd_getstringsize(" Split 2 ", &w, &h); - rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2, - " Split 2 "); + rb->snprintf(buf, sizeof(buf), " %s 2 ", str(P_LANG_SPLIT)); + rb->talk_id(P_LANG_SPLIT, true); + rb->talk_number(2, true); + rb->lcd_getstringsize(buf, &w, &h); + rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2, buf); rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2, w,h); rb->sleep(HZ*2); @@ -1546,10 +1564,11 @@ struct game_context bj; bool exit = false; unsigned int position; - char str[19]; + char str[64]; (void)parameter; rb = api; + plugin_use_lang(rb, USER_BLACKJACK, blackjack_language_builtin); #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); @@ -1559,18 +1578,20 @@ blackjack_loadscores(&bj); rb->lcd_setfont(FONT_SYSFIXED); + rb->talk_id(P_LANG_BLACKJACK, false); while(!exit) { switch(blackjack(&bj)){ case BJ_LOSE: - rb->splash(HZ, "Not enough money to continue"); + rb->splash(HZ, ID2P(P_LANG_NEED_MONEY_CONTINUE)); /* fall through to BJ_END */ case BJ_END: if(!bj.resume) { if((position = blackjack_recordscore(&bj))) { - rb->snprintf(str, 19, "New high score #%d!", position); - rb->splash(HZ*2, str); + rb->talk_id(P_LANG_NEW_HIGH_SCORE, true); + rb->talk_number(position, true); + rb->splash(HZ*2, str(P_LANG_NEW_HIGH_SCORE), position); } } break; @@ -1581,7 +1602,7 @@ case BJ_QUIT: if(bj.dirty) { - rb->splash(HZ, "Saving high scores..."); + rb->splash(HZ, ID2P(P_LANG_SAVING_HIGH_SCORES)); blackjack_savescores(&bj); } exit = true; Index: apps/talk.c =================================================================== --- apps/talk.c (revision 18265) +++ apps/talk.c (working copy) @@ -178,6 +178,9 @@ } else { /* normal use of the first table */ + if (id > LANG_LAST_INDEX_IN_ARRAY) /* id is a plugin string */ + id--; + if (id >= p_voicefile->id1_max) return NULL; /* must be newer than we have */ } Index: apps/plugin.c =================================================================== --- apps/plugin.c (revision 18265) +++ apps/plugin.c (working copy) @@ -37,6 +37,7 @@ #include "logf.h" #include "option_select.h" #include "talk.h" +#include "language.h" #if CONFIG_CHARGING #include "power.h" @@ -60,16 +61,17 @@ extern unsigned char pluginbuf[]; #include "bitswap.h" #endif +void plugin_dump_mem(void); /* for actual plugins only, not for codecs */ -static bool plugin_loaded = false; -static int plugin_size = 0; +static int plugin_used_buffer = 0; static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */ static char current_plugin[MAX_PATH]; char *plugin_get_current_filename(void); extern struct thread_entry threads[MAXTHREADS]; +extern unsigned char** plugin_language_strings; static const struct plugin_api rockbox_api = { @@ -605,8 +607,18 @@ #ifdef HAVE_TAGCACHE tagcache_get_numeric, #endif - gui_syncyesno_run, + lang_load_helper, + &language_strings[0], +#ifdef SIMULATOR + &vp_dummy[0], +#endif + &plugin_language_strings, + lang_set_plugin_strings, + talk_id, + talk_force_enqueue_next, + talk_idarray, + talk_number, }; int plugin_load(const char* plugin, const void* parameter) @@ -635,7 +647,7 @@ return PLUGIN_OK; } pfn_tsr_exit = NULL; - plugin_loaded = false; + plugin_used_buffer = 0; } gui_syncsplash(0, ID2P(LANG_WAIT)); @@ -695,16 +707,12 @@ gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION)); return -1; } - plugin_size = hdr->end_addr - pluginbuf; + plugin_used_buffer = hdr->end_addr - pluginbuf; /* zero out bss area only, above guards end of pluginbuf */ - if (plugin_size > readsize) - memset(pluginbuf + readsize, 0, plugin_size - readsize); + if (plugin_used_buffer > readsize) + memset(pluginbuf + readsize, 0, plugin_used_buffer - readsize); #endif - - plugin_loaded = true; - - #if defined HAVE_LCD_BITMAP && LCD_DEPTH > 1 old_backdrop = lcd_get_backdrop(); #endif @@ -717,8 +725,9 @@ #endif invalidate_icache(); - + rc = hdr->entry_point(&rockbox_api, parameter); + plugin_dump_mem(); button_clear_queue(); @@ -755,7 +764,7 @@ #endif if (pfn_tsr_exit == NULL) - plugin_loaded = false; + plugin_used_buffer = 0; sim_plugin_close(pd); @@ -777,23 +786,11 @@ being used. If no plugin is loaded, returns the entire plugin buffer */ void* plugin_get_buffer(size_t *buffer_size) { - int buffer_pos; - - if (plugin_loaded) - { - if (plugin_size >= PLUGIN_BUFFER_SIZE) - return NULL; - - *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size; - buffer_pos = plugin_size; - } - else - { - *buffer_size = PLUGIN_BUFFER_SIZE; - buffer_pos = 0; - } - - return &pluginbuf[buffer_pos]; + if(plugin_used_buffer >= PLUGIN_BUFFER_SIZE) + return NULL; + + *buffer_size = PLUGIN_BUFFER_SIZE - plugin_used_buffer; + return &pluginbuf[plugin_used_buffer]; } /* Returns a pointer to the mp3 buffer. @@ -841,3 +838,13 @@ { return current_plugin; } + +void plugin_dump_mem(void) +{ + unsigned int fd; + + /* write out the high scores to the save file */ + fd = open("/plugin_dump.bin", O_WRONLY|O_CREAT); + write(fd, pluginbuf, PLUGIN_BUFFER_SIZE); + close(fd); +} Index: apps/plugin.h =================================================================== --- apps/plugin.h (revision 18265) +++ apps/plugin.h (working copy) @@ -126,6 +126,11 @@ #define PREFIX(_x_) _x_ #endif +#if defined(SIMULATOR) && defined(PLUGIN) +#undef VIRT_PTR +#define VIRT_PTR rb->vp_dummy +#endif + #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ @@ -759,11 +764,22 @@ #ifdef HAVE_TAGCACHE long (*tagcache_get_numeric)(const struct tagcache_search *tcs, int tag); #endif - enum yesno_res (*gui_syncyesno_run)(const struct text_message * main_message, const struct text_message * yes_message, const struct text_message * no_message); - + int (*lang_load_helper)(const char *filename, const unsigned char *builtin, + unsigned char **dest, unsigned char *buffer, + unsigned int user, unsigned int max); + unsigned char **language_strings; +#ifdef SIMULATOR + unsigned char *vp_dummy; +#endif + unsigned char ***plugin_language_strings; + void (*lang_set_plugin_strings)(unsigned char** strings_ptr); + int (*talk_id)(int32_t id, bool enqueue); + void (*talk_force_enqueue_next)(void); + int (*talk_idarray)(long *ids, bool enqueue); + int (*talk_number)(long n, bool enqueue); }; /* plugin header */