1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * robotfindskitten: A Zen simulation
12 * Copyright (C) 1997,2000 Leonard Richardson
13 * leonardr@segfault.org
14 * http://www.crummy.com/devel/
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of
19 * the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or EXISTANCE OF KITTEN. See the GNU General
24 * Public License for more details.
26 * http://www.gnu.org/copyleft/gpl.html
28 * Ported to Rockbox 2007 by Jonas Häggqvist
32 #include "pluginlib_actions.h"
34 /* This macros must always be included. Should be placed at the top by
35 convention, although the actual position doesn't matter */
38 /*The messages go in a separate file because they are collectively
39 huge, and you might want to modify them. It would be nice to load
40 the messages from a text file at run time.*/
41 #include "robotfindskitten_messages.h"
46 #define RFK_VERSION "v1.4142135.406"
48 /* Button definitions stolen from maze.c */
49 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
50 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
51 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
52 # undef __PLUGINLIB_ACTIONS_H__
53 # define RFK_QUIT (BUTTON_SELECT | BUTTON_MENU)
54 # define RFK_RIGHT BUTTON_RIGHT
55 # define RFK_LEFT BUTTON_LEFT
56 # define RFK_UP BUTTON_MENU
57 # define RFK_DOWN BUTTON_PLAY
58 # define RFK_RRIGHT (BUTTON_RIGHT | BUTTON_REPEAT)
59 # define RFK_RLEFT (BUTTON_LEFT | BUTTON_REPEAT)
60 # define RFK_RUP (BUTTON_MENU | BUTTON_REPEAT)
61 # define RFK_RDOWN (BUTTON_PLAY | BUTTON_REPEAT)
64 # define RFK_QUIT PLA_QUIT
65 # define RFK_RIGHT PLA_RIGHT
66 # define RFK_LEFT PLA_LEFT
67 # define RFK_UP PLA_UP
68 # define RFK_DOWN PLA_DOWN
69 # define RFK_RRIGHT PLA_RIGHT_REPEAT
70 # define RFK_RLEFT PLA_LEFT_REPEAT
71 # define RFK_RUP PLA_UP_REPEAT
72 # define RFK_RDOWN PLA_DOWN_REPEAT
75 /*Constants for our internal representation of the screen.*/
80 /*Screen dimensions.*/
82 #define X_MAX ((LCD_WIDTH/SYSFONT_WIDTH) - 1)
84 #define Y_MAX ((LCD_HEIGHT/SYSFONT_HEIGHT) - 1)
89 #define ROBOT_COLOR LCD_DARKGRAY
90 const unsigned colors
[NUM_COLORS
] = {
91 LCD_RGBPACK(255, 255, 0), /* Yellow */
92 LCD_RGBPACK(0, 255, 255), /* Cyan */
93 LCD_RGBPACK(255, 0, 255), /* Purple */
94 LCD_RGBPACK(0, 0, 255), /* Blue */
95 LCD_RGBPACK(255, 0, 0), /* Red */
96 LCD_RGBPACK(0, 255, 0), /* Green */
100 #define ROBOT_COLOR LCD_DARKGRAY
101 const unsigned colors
[NUM_COLORS
] = {
108 #define ROBOT_COLOR 0
109 const unsigned colors
[NUM_COLORS
] = {
112 #endif /* HAVE_LCD_COLOR */
114 /*Macros for generating numbers in different ranges*/
115 #define randx() (rb->rand() % X_MAX) + 1
116 #define randy() (rb->rand() % (Y_MAX-Y_MIN+1))+Y_MIN /*I'm feeling randy()!*/
117 #define randchar() rb->rand() % (126-'!'+1)+'!';
118 #define randcolor() rb->rand() % NUM_COLORS
119 #define randbold() (rb->rand() % 2 ? TRUE:FALSE)
121 /*Row constants for the animation*/
123 #define ANIMATION_MEET (X_MAX/3)*2
124 #define ANIMATION_LENGTH 4
126 /*This struct contains all the information we need to display an object
138 *Function definitions
141 /*Initialization and setup functions*/
142 static void initialize_arrays(void);
143 static void initialize_robot(void);
144 static void initialize_kitten(void);
145 static void initialize_bogus(void);
146 static void initialize_screen(void);
147 static void instructions(void);
148 static void finish(int sig
);
151 static void play_game(void);
152 static void process_input(int);
155 static void pause(void);
156 static int validchar(char);
157 static void play_animation(int);
159 /*Global variables. Bite me, it's fun.*/
161 screen_object kitten
;
163 #if X_MAX*Y_MAX < 200
168 screen_object bogus
[NUM_BOGUS
];
169 unsigned short bogus_messages
[NUM_BOGUS
];
170 bool used_messages
[MESSAGES
];
174 /* This array contains our internal representation of the screen. The
175 array is bigger than it needs to be, as we don't need to keep track
176 of the first few rows of the screen. But that requires making an
177 offset function and using that everywhere. So not right now. */
178 int screen
[X_MAX
+ 1][Y_MAX
+ 1];
180 /* here is a global api struct pointer. while not strictly necessary,
181 it's nice not to have to pass the api pointer in all function calls
183 static struct plugin_api
* rb
;
185 /******************************************************************************
187 * Begin meaty routines that do the dirty work.
189 *****************************************************************************/
191 MEM_FUNCTION_WRAPPERS(rb
)
193 static void drawchar(int x
, int y
, char c
)
196 rb
->snprintf(str
, sizeof(str
), "%c", c
);
197 rb
->lcd_putsxy(x
*SYSFONT_WIDTH
, y
*SYSFONT_HEIGHT
, str
);
200 static void draw(screen_object o
)
203 unsigned oldforeground
;
204 oldforeground
= rb
->lcd_get_foreground();
205 rb
->lcd_set_foreground(o
.color
);
206 drawchar(o
.x
, o
.y
, o
.character
);
207 rb
->lcd_set_foreground(oldforeground
);
209 drawchar(o
.x
, o
.y
, o
.character
);
213 static void message(char * str
)
215 rb
->lcd_puts_scroll(0, ADV_ROW
, str
);
218 static void refresh(void)
224 *play_game waits in a loop getting input and sending it to process_input
226 static void play_game()
230 int input
= 0; /* Not sure what a reasonable initial value is */
231 #ifdef __PLUGINLIB_ACTIONS_H__
232 const struct button_mapping
*plugin_contexts
[] = {generic_directions
, generic_actions
};
235 while (input
!= RFK_QUIT
&& exit_rfk
== false)
237 process_input(input
);
239 /*Redraw robot, where applicable. We're your station, robot.*/
240 if (!(old_x
== robot
.x
&& old_y
== robot
.y
))
242 /*Get rid of the old robot*/
243 drawchar(old_x
, old_y
, ' ');
244 screen
[old_x
][old_y
] = EMPTY
;
246 /*Meet the new robot, same as the old robot.*/
249 screen
[robot
.x
][robot
.y
] = ROBOT
;
254 #ifdef __PLUGINLIB_ACTIONS_H__
255 input
= pluginlib_getaction(rb
, TIMEOUT_BLOCK
, plugin_contexts
, 2);
257 input
= rb
->button_get(true);
265 *Given the keyboard input, process_input interprets it in terms of moving,
266 *touching objects, etc.
268 static void process_input(int input
)
270 int check_x
= robot
.x
;
271 int check_y
= robot
.y
;
293 /*Check for going off the edge of the screen.*/
294 if (check_y
< Y_MIN
|| check_y
> Y_MAX
|| check_x
< X_MIN
|| check_x
> X_MAX
)
296 return; /*Do nothing.*/
301 * disabled because it breaks the scrolling for some reason
303 /* rb->lcd_puts_scroll(0, ADV_ROW, " "); */
305 /*Check for collision*/
306 if (screen
[check_x
][check_y
] != EMPTY
)
308 switch (screen
[check_x
][check_y
])
311 /*We didn't move, or we're stuck in a
312 time warp or something.*/
314 case KITTEN
: /*Found it!*/
315 play_animation(input
);
316 /* Wait for the user to click something */
319 default: /*We hit a bogus object; print its message.*/
320 message(messages
[bogus_messages
[screen
[check_x
][check_y
]-2]]);
327 /*Otherwise, move the robot.*/
332 /*finish is called upon signal or progam exit*/
333 static void finish(int sig
)
339 /******************************************************************************
341 * Begin helper routines
343 *****************************************************************************/
350 button
= rb
->button_get(true);
351 while( ( button
== BUTTON_NONE
)
352 || ( button
& (BUTTON_REL
|BUTTON_REPEAT
) ) );
355 static int validchar(char a
)
367 static void play_animation(int input
)
372 /*The grand cinema scene.*/
373 rb
->lcd_puts_scroll(0, ADV_ROW
, " ");
375 if (input
== RFK_RIGHT
|| input
== RFK_DOWN
|| input
== RFK_RRIGHT
|| input
== RFK_RDOWN
) {
385 left
.x
= ANIMATION_MEET
- ANIMATION_LENGTH
- 1;
386 right
.x
= ANIMATION_MEET
+ ANIMATION_LENGTH
;
388 for (counter
= ANIMATION_LENGTH
; counter
> 0; counter
--)
392 /* Clear the previous position (empty the first time) */
393 drawchar(left
.x
- 1, left
.y
, ' ');
394 drawchar(right
.x
+ 1, right
.y
, ' ');
401 message("You found kitten! Way to go, robot!");
406 /******************************************************************************
408 * Begin initialization routines (called before play begins).
410 *****************************************************************************/
412 static void instructions()
415 int y
= MARGIN
, space_w
, width
, height
;
416 unsigned short x
= MARGIN
, i
= 0;
417 #define WORDS (sizeof instructions / sizeof (char*))
418 static char* instructions
[] = {
420 /* Not sure if we want to include this? */
421 "robotfindskitten", RFK_VERSION
, "", "",
422 "By", "the", "illustrious", "Leonard", "Richardson", "(C)", "1997,", "2000", "",
423 "Written", "originally", "for", "the", "Nerth", "Pork", "robotfindskitten", "contest", "", "",
425 "In", "this", "game", "you", "are", "robot", "(#).", "Your", "job", "is", "to", "find", "kitten.", "This", "task", "is", "complicated", "by", "the", "existence", "of", "various", "things", "which", "are", "not", "kitten.", "Robot", "must", "touch", "items", "to", "determine", "if", "they", "are", "kitten", "or", "not.", "",
426 "The", "game", "ends", "when", "robotfindskitten.", "", "",
427 "Press", "any", "key", "to", "start",
429 rb
->lcd_clear_display();
430 rb
->lcd_getstringsize(" ", &space_w
, &height
);
431 for (i
= 0; i
< WORDS
; i
++) {
432 rb
->lcd_getstringsize(instructions
[i
], &width
, NULL
);
433 /* Skip to next line if the current one can't fit the word */
434 if (x
+ width
> LCD_WIDTH
- MARGIN
) {
438 /* .. or if the word is the empty string */
439 if (rb
->strcmp(instructions
[i
], "") == 0) {
444 /* We filled the screen */
445 if (y
+ height
> LCD_HEIGHT
- MARGIN
) {
448 rb
->lcd_clear_display();
450 rb
->lcd_putsxy(x
, y
, instructions
[i
]);
451 x
+= width
+ space_w
;
456 static void initialize_arrays()
458 unsigned int counter
, counter2
;
461 /*Initialize the empty object.*/
465 empty
.color
= LCD_BLACK
;
470 empty
.character
= ' ';
472 for (counter
= 0; counter
<= X_MAX
; counter
++)
474 for (counter2
= 0; counter2
<= Y_MAX
; counter2
++)
476 screen
[counter
][counter2
] = EMPTY
;
480 /*Initialize the other arrays.*/
481 for (counter
= 0; counter
< MESSAGES
; counter
++)
483 used_messages
[counter
] = false;
485 for (counter
= 0; counter
< NUM_BOGUS
; counter
++)
487 bogus_messages
[counter
] = 0;
488 bogus
[counter
] = empty
;
492 /*initialize_robot initializes robot.*/
493 static void initialize_robot()
495 /*Assign a position to the player.*/
499 robot
.character
= '#';
500 robot
.color
= ROBOT_COLOR
;
502 screen
[robot
.x
][robot
.y
] = ROBOT
;
505 /*initialize kitten, well, initializes kitten.*/
506 static void initialize_kitten()
508 /*Assign the kitten a unique position.*/
513 } while (screen
[kitten
.x
][kitten
.y
] != EMPTY
);
515 /*Assign the kitten a character and a color.*/
517 kitten
.character
= randchar();
518 } while (!(validchar(kitten
.character
)));
519 screen
[kitten
.x
][kitten
.y
] = KITTEN
;
521 kitten
.color
= colors
[randcolor()];
522 kitten
.bold
= randbold();
525 /*initialize_bogus initializes all non-kitten objects to be used in this run.*/
526 static void initialize_bogus()
529 for (counter
= 0; counter
< NUM_BOGUS
; counter
++)
532 bogus
[counter
].color
= colors
[randcolor()];
533 bogus
[counter
].bold
= randbold();
535 /*Give it a character.*/
537 bogus
[counter
].character
= randchar();
538 } while (!(validchar(bogus
[counter
].character
)));
540 /*Give it a position.*/
543 bogus
[counter
].x
= randx();
544 bogus
[counter
].y
= randy();
545 } while (screen
[bogus
[counter
].x
][bogus
[counter
].y
] != EMPTY
);
547 screen
[bogus
[counter
].x
][bogus
[counter
].y
] = counter
+2;
549 /*Find a message for this object.*/
551 index
= rb
->rand() % MESSAGES
;
552 } while (used_messages
[index
] != false);
553 bogus_messages
[counter
] = index
;
554 used_messages
[index
] = true;
559 /*initialize_screen paints the screen.*/
560 static void initialize_screen()
566 *Print the status portion of the screen.
568 rb
->lcd_clear_display();
569 rb
->lcd_setfont(FONT_SYSFIXED
);
570 rb
->snprintf(buf
, sizeof(buf
), "robotfindskitten %s", RFK_VERSION
);
571 rb
->lcd_puts_scroll(0, 0, buf
);
574 /*Draw a line across the screen.*/
575 for (counter
= X_MIN
; counter
<= X_MAX
+ 1; counter
++)
577 drawchar(counter
, ADV_ROW
+1, '_');
581 *Draw all the objects on the playing field.
583 for (counter
= 0; counter
< NUM_BOGUS
; counter
++)
585 draw(bogus
[counter
]);
595 /* this is the plugin entry point */
596 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
603 rb
->srand(*rb
->current_tick
);
608 * Now we initialize the various game objects.
615 * Set up white-on-black screen on color targets
618 rb
->lcd_set_backdrop(NULL
);
619 rb
->lcd_set_foreground(LCD_WHITE
);
620 rb
->lcd_set_background(LCD_BLACK
);
632 rb
->lcd_setfont(FONT_UI
);