661 lines
19 KiB
C
661 lines
19 KiB
C
#include <sysinit.h>
|
|
#include <string.h>
|
|
|
|
#include "basic/basic.h"
|
|
#include "basic/random.h"
|
|
#include "basic/config.h"
|
|
#include "lcd/render.h"
|
|
#include "lcd/backlight.h"
|
|
#include "lcd/allfonts.h"
|
|
#include "funk/nrf24l01p.h"
|
|
|
|
|
|
#define POEM_ID 2
|
|
|
|
#define BTN_WAKEUP (1 << 5)
|
|
#define BTN_STANDBY (1 << 6)
|
|
|
|
#define POEM_FONT_WIDTH 5
|
|
#define POEM_FONT_HEIGHT 8
|
|
#define POEM_FONT Font_5x8
|
|
|
|
#define POEM_COUNT 5u
|
|
#define POEM_VERSE_COUNT 4u
|
|
#define POEM_MAX_LINE_COUNT (RESY / POEM_FONT_HEIGHT)
|
|
#define POEM_LINE_LIMIT ((RESX - 4) / POEM_FONT_WIDTH)
|
|
|
|
|
|
#define POEM_PACKET_RETRIES 10
|
|
|
|
typedef enum packet_type_e {
|
|
PCKT_WINNER0,
|
|
PCKT_WINNER1,
|
|
PCKT_WINNER2,
|
|
PCKT_WINNER3,
|
|
PCKT_WINNER4,
|
|
PCKT_WINNER5,
|
|
PCKT_WINNER6,
|
|
PCKT_WINNER7,
|
|
PCKT_WAKEUP,
|
|
PCKT_STANDBY,
|
|
PCKT_NONE
|
|
} packet_type_t;
|
|
|
|
|
|
static char const *const poem_gPackets[10] = {
|
|
"winner0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"winner1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"winner2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"winner3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"winner4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"winner5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"winner6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"winner7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"wake up\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
"standby\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
};
|
|
|
|
|
|
typedef enum poem_state_e {
|
|
POEM_STATE_STANDBY,
|
|
POEM_STATE_USAGE,
|
|
POEM_STATE_PLAYING,
|
|
POEM_STATE_WON
|
|
} poem_state_t;
|
|
|
|
|
|
typedef struct poem_break_marker_s {
|
|
unsigned int nStart;
|
|
unsigned int nStop;
|
|
} poem_break_marker_t;
|
|
|
|
|
|
typedef struct poem_s {
|
|
char const * const pszVerses[POEM_VERSE_COUNT];
|
|
unsigned int nLineCounts[POEM_VERSE_COUNT];
|
|
unsigned int nPermut[POEM_VERSE_COUNT];
|
|
poem_break_marker_t pszMarkers[POEM_VERSE_COUNT][POEM_MAX_LINE_COUNT];
|
|
} poem_t;
|
|
|
|
|
|
static poem_t g_poem_aPoems[POEM_COUNT]= {
|
|
#if POEM_ID == 0
|
|
// Goethe - An den Mond, 3. Vers
|
|
{{"Jeden Nachklang fuehlt mein Herz",
|
|
"Froh und trueber Zeit,",
|
|
"Wandle zwischen Freud' und Schmerz",
|
|
"In der Einsamkeit."}},
|
|
|
|
// Goethe - Gefunden, 3. Vers
|
|
{{"Ich wollt es brechen,",
|
|
"Da sagt es fein:",
|
|
"Soll ich zum Welken",
|
|
"Gebrochen sein?"}},
|
|
|
|
// Grillparzer - In der Fremde, 2. Vers
|
|
{{"So willst Du denn nach Hause?",
|
|
"O nein! Nur nicht nach Haus!",
|
|
"Dort stirbt des Lebens Leben",
|
|
"Im Einerlei mir aus."}},
|
|
|
|
// Friedrich Schiller - Pilgrim, 1. Vers
|
|
{{"Noch in meines Lebens Lenze",
|
|
"War ich, und ich wandert' aus,",
|
|
"Und der Jugend frohe Taenze",
|
|
"Liess ich in des Vaters Haus."}},
|
|
|
|
// Frank Wedekind - Erdgeist, 2. Vers
|
|
{{"Meide nicht die ird'schen Schaetze:",
|
|
"Wo sie liegen, nimm sie mit.",
|
|
"Hat die Welt doch nur Gesetze,",
|
|
"Dass man sie mit Fuessen tritt."}},
|
|
|
|
#elif POEM_ID == 1
|
|
|
|
// Clemens Brentano - Loreley
|
|
{{"Zu Bacharach am Rheine",
|
|
"Wohnt eine Zauberin,",
|
|
"Die war so schoen und feine",
|
|
"Und riss viel Herzen hin."}},
|
|
|
|
// Wilhelm Busch - Frueher, da ich unerfahren
|
|
{{"Frueher, da ich unerfahren",
|
|
"Und bescheidner war als heute,",
|
|
"Hatten meine hoechste Achtung",
|
|
"Andre Leute."}},
|
|
|
|
// Heinz Erhardt - Warum die Zitronen sauer wurden
|
|
{{"Bis sie einst sprachen: 'Wir Zitronen,",
|
|
"wir wollen gross sein wie Melonen!",
|
|
"Auch finden wir das Gelb abscheulich,",
|
|
"wir wollen rot sein oder blaeulich!'"}},
|
|
|
|
// Joseph von Eichendorff - Mondnacht
|
|
{{"Die Luft ging durch die Felder,",
|
|
"Die Aehren wogten sacht,",
|
|
"Es rauschten leis' die Waelder,",
|
|
"So sternklar war die Nacht."}},
|
|
|
|
// Theodor Fontane - Trost
|
|
{{"Harre, hoffe. Nicht vergebens",
|
|
"zaehlest du der Stunden Schlag:",
|
|
"Wechsel ist das Los des Lebens,",
|
|
"Und - es kommt ein andrer Tag."}},
|
|
|
|
#elif POEM_ID == 2
|
|
|
|
// Goethe - Der Zauberlehrling
|
|
{{"Ach, da kommt der Meister!",
|
|
"Herr, die Not ist gross!",
|
|
"Die ich rief, die Geister,",
|
|
"Werd ich nun nicht los."}},
|
|
|
|
// Schiller - Das Lied von der Glocke
|
|
{{"Fest gemauert in der Erden",
|
|
"Steht die Form, aus Lehm gebrannt.",
|
|
"Heute muss die Glocke werden!",
|
|
"Frisch, Gesellen, seid zur Hand!"}},
|
|
|
|
// Hermann Hesse - Im Nebel
|
|
{{"Voll von Freunden war mir die Welt",
|
|
"Als noch mein Leben licht war;",
|
|
"Nun, da der Nebel faellt,",
|
|
"Ist keiner mehr sichtbar."}},
|
|
|
|
// irgend ein Kinderlied
|
|
{{"Schoen ist der Zylinderhut",
|
|
"Wenn man ihn besitzen tut",
|
|
"Doch von ganz besondrer Guete",
|
|
"Sind stets zwei Zylinderhuete"}},
|
|
|
|
// Conrad Ferdinand Meyer - Alles war ein Spiel
|
|
{{"In diesen Liedern suche du",
|
|
"Nach keinem ernsten Ziel!",
|
|
"Ein wenig Schmerz, ein wenig Lust,",
|
|
"Und alles war ein Spiel."}},
|
|
|
|
#elif POEM_ID == 3
|
|
|
|
// Friedrich Nietzsche - Vereinsamt
|
|
{{"Die Kraehen schrein",
|
|
"Und ziehen schwirren Flugs zur Stadt:",
|
|
"Bald wird es schnein, -",
|
|
"Wohl dem, der jetzt noch - Heimat hat!"}},
|
|
|
|
// Christian Morgenstern - Der Werwolf
|
|
{{"Dem Werwolf schmeichelten die Faelle,",
|
|
"er rollte seine Augenbaelle.",
|
|
"Indessen, bat er, fuege doch",
|
|
"zur Einzahl auch die Mehrzahl noch!"}},
|
|
|
|
// Wilhelm Busch - Dummheit, die man bei den anderen sieht
|
|
{{"Wenn andere klueger sind als wir,",
|
|
"Das macht uns selten nur Plaesier,",
|
|
"Doch die Gewissheit, dass sie duemmer,",
|
|
"Erfreut fast immer."}},
|
|
|
|
// August von Kotzebue - Gesellschaftslied, 2. Vers
|
|
{{"Wir sitzen so froehlich beisammen",
|
|
"Wir haben uns alle so lieb,",
|
|
"Wir heitern einander das Leben,",
|
|
"Ach wenn es doch immer so blieb'!"}},
|
|
|
|
// Gotthold Ephraim Lessing - Antwort eines trunknen Dichters, 1. Vers
|
|
{{"Ein trunkner Dichter leerte",
|
|
"Sein Glas auf jeden Zug;",
|
|
"Ihn warnte sein Gefaehrte:",
|
|
"Hoer' auf! du hast genug."}},
|
|
|
|
#elif POEM_ID == 4
|
|
|
|
// Hermann von Lingg - Das Krokodil, 1. Vers
|
|
{{"Im heil'gen Teich zu Singapur,",
|
|
"Da liegt ein altes Krokodil",
|
|
"Von aeusserst graemlicher Natur",
|
|
"Und kaut an einem Lotosstiel."}},
|
|
|
|
// Hermann Loens - Wegewarte, 2. Vers
|
|
{{"Ich stand an dem Wege,",
|
|
"Hielt auf meine Hand,",
|
|
"Du hast Deine Augen",
|
|
"Von mir abgewandt."}},
|
|
|
|
// Christian Morgenstern - An meine Taschenuhr, 1. und einziger Vers
|
|
{{"Du schlimme Uhr, du gehst mir viel zu schnell;",
|
|
"und doch - dich schauend, sah ich selber hell.",
|
|
"Unschuldig Raederwerk, was schalt ich dich?",
|
|
"Ich geh zu langsam, ach zu langsam - ich."}},
|
|
|
|
// Eduard Moerike - Jaegerlied, 2.Vers
|
|
{{"In die Luefte hoch der Reiher steigt,",
|
|
"dahin weder Pfeil noch Kugel fleugt:",
|
|
"Tausendmal so hoch und so geschwind",
|
|
"die Gedanken treuer Liebe sind."}},
|
|
|
|
// Erich Muehsam - Liebesweh, 3. Vers
|
|
{{"Ach, es ist der Traum der Liebe,",
|
|
"den ich durch die Seele siebe.",
|
|
"Ach, es ist der Liebe Weh,",
|
|
"das mich zwickt vom Kopf zur Zeh."}},
|
|
|
|
#elif POEM_ID == 5
|
|
|
|
// Wilhelm Mueller - Der Glockenguss zu Breslau, 6. Vers
|
|
{{"Wie hat der gute Meister",
|
|
"So treu das Werk bedacht!",
|
|
"Wie hat er seine Haende",
|
|
"Geruehrt bei Tag und Nacht!"}},
|
|
|
|
// Ludwig Pfau - Der Geiger von Oppenau, 2. Vers
|
|
{{"Wo seine Fiedel geklungen,",
|
|
"Da konnte kein Fuss mehr stehn,",
|
|
"Da sprangen die Alten und Jungen,",
|
|
"Die Stube fing an zu drehn."}},
|
|
|
|
// Robert Reinick - Der Faule, 2. Vers
|
|
{{"Doch die Zeit wird lang mir werden,",
|
|
"Und wie bring' ich sie herum?",
|
|
"Spitz! komm her! dich will ich lehren",
|
|
"Hund, du bist mir viel zu dumm!"}},
|
|
|
|
// Rainer Maria Rilke - Herbsttag, 2. Vers
|
|
{{"Befiehl den letzten Fruechten voll zu sein;",
|
|
"gib ihnen noch zwei suedlichere Tage,",
|
|
"draenge sie zur Vollendung hin und jage",
|
|
"die letzte Suesse in den schweren Wein."}},
|
|
|
|
// Joachim Ringelnatz - Ehrgeiz
|
|
{{"Ich habe meinen Soldaten aus Blei",
|
|
"Als Kind Verdienstkreuzchen eingeritzt.",
|
|
"Mir selber ging alle Ehre vorbei,",
|
|
"Bis auf zwei Orden, die jeder besitzt."}}
|
|
#endif
|
|
};
|
|
|
|
|
|
/**
|
|
* Prepares markers for line wrapping and determines the number of lines
|
|
* required to display a verse.
|
|
*/
|
|
static void poem_prepareLineWrappingMarkers(void) {
|
|
for (unsigned int iPoem = 0; iPoem < POEM_COUNT; ++iPoem) {
|
|
for (unsigned int iVerse = 0; iVerse < POEM_VERSE_COUNT; ++iVerse) {
|
|
char const * const psz = g_poem_aPoems[iPoem].pszVerses[iVerse];
|
|
size_t const nLen = strlen(psz);
|
|
unsigned int nPos = 0, nCharCnt = 0, nLineCount = 0;
|
|
int nLastSpc = -1;
|
|
|
|
poem_break_marker_t *pMarker =
|
|
&g_poem_aPoems[iPoem].pszMarkers[iVerse][nLineCount];
|
|
while ((nPos < nLen) && (nLineCount < POEM_MAX_LINE_COUNT)) {
|
|
if (nCharCnt < POEM_LINE_LIMIT && (nPos != (nLen - 1))) {
|
|
if (psz[nPos] == ' ') {
|
|
nLastSpc = nPos;
|
|
}
|
|
++nCharCnt;
|
|
} else {
|
|
pMarker->nStart = nPos - nCharCnt;
|
|
if (nPos == (nLen - 1)) {
|
|
pMarker->nStop = nPos;
|
|
} else if (nLastSpc < (nPos - nCharCnt)) {
|
|
pMarker->nStop = nPos - 1;
|
|
} else {
|
|
pMarker->nStop = nLastSpc;
|
|
nPos = nLastSpc;
|
|
}
|
|
pMarker = &g_poem_aPoems[iPoem].pszMarkers[iVerse][++nLineCount];
|
|
nCharCnt = 0;
|
|
}
|
|
++nPos;
|
|
}
|
|
g_poem_aPoems[iPoem].nLineCounts[iVerse] = nLineCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Prints a physical line (that is one row of displayed characters) from a given
|
|
* poem and verse.
|
|
* @param pPoem The poem where to look for that line.
|
|
* @param nVerse The verse where the to be printed line resides.
|
|
* @param nLine The position (counting from 0) of that line within that verse.
|
|
* @param y The vertical offset where text should be rendered.
|
|
*/
|
|
static void poem_printLine(poem_t const *const pPoem, unsigned int nVerse,
|
|
unsigned int nLine, int y) {
|
|
char pszLine[POEM_LINE_LIMIT + 1] = { 0 };
|
|
poem_break_marker_t const * const pMarker =
|
|
&pPoem->pszMarkers[nVerse][nLine];
|
|
for (unsigned int k = pMarker->nStart; k <= pMarker->nStop; ++k) {
|
|
pszLine[k - pMarker->nStart] = pPoem->pszVerses[nVerse][k];
|
|
}
|
|
DoString(2, y, pszLine);
|
|
}
|
|
|
|
|
|
/**
|
|
* Shuffles the verses of a given poem.
|
|
* @param pPoem The poem whose verses need to be shuffled.
|
|
*/
|
|
static void poem_initPermutation(poem_t *const pPoem) {
|
|
for (unsigned int i = POEM_VERSE_COUNT; i--;) {
|
|
pPoem->nPermut[i] = i;
|
|
}
|
|
while ((pPoem->nPermut[0] < pPoem->nPermut[1])
|
|
&& (pPoem->nPermut[1] < pPoem->nPermut[2])
|
|
&& (pPoem->nPermut[2] < pPoem->nPermut[3])) {
|
|
for (unsigned int i = 4; i--;) {
|
|
unsigned int const nIndexA = getRandom() % POEM_VERSE_COUNT;
|
|
unsigned int const nIndexB = getRandom() % POEM_VERSE_COUNT;
|
|
|
|
unsigned int nSwap = pPoem->nPermut[nIndexA];
|
|
pPoem->nPermut[nIndexA] = pPoem->nPermut[nIndexB];
|
|
pPoem->nPermut[nIndexB] = nSwap;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t poem_identifyPacket(uint8_t *packet){
|
|
uint8_t input = BTN_NONE;
|
|
if (strncmp((char *)packet, poem_gPackets[PCKT_STANDBY], 8) == 0) {
|
|
input = BTN_STANDBY;
|
|
} else if (strncmp((char *)packet, poem_gPackets[PCKT_WAKEUP], 8) == 0) {
|
|
input = BTN_WAKEUP;
|
|
}
|
|
return input;
|
|
}
|
|
|
|
|
|
/**
|
|
* Watches for both joystick movements and standby NRF packets. It's blocks the
|
|
* control flow as long as there are neither appropriate joystick activities nor
|
|
* standby/wake up packets received.
|
|
* @param filter A mask of events to which this function should react.
|
|
* @return One of BTN_(UP|DOWN|LEFT|RIGHT|ENTER|STANDBY|WAKEUP).
|
|
*/
|
|
uint8_t poem_getInputBlocking(uint8_t filter) {
|
|
uint8_t pkt[32];
|
|
uint8_t input = BTN_NONE;
|
|
nrf_rcv_pkt_start();
|
|
do {
|
|
if ((nrf_rcv_pkt_poll(sizeof(pkt), pkt) != 32) ||
|
|
!((input = poem_identifyPacket(pkt)) & filter)) {
|
|
input = getInput();
|
|
}
|
|
} while (!(filter & input));
|
|
nrf_rcv_pkt_end();
|
|
return input;
|
|
}
|
|
|
|
|
|
/**
|
|
* Watches for both joystick movements and standby NRF packets. It returns
|
|
* BTN_NONE if there's neither a NRF packet nor joystick input.
|
|
* @return One of BTN_(NONE|UP|DOWN|LEFT|RIGHT|ENTER|STANDBY|WAKEUP).
|
|
*/
|
|
uint8_t poem_getInputNonBlocking(void) {
|
|
uint8_t pkt[32];
|
|
uint8_t input;
|
|
// wait up to 200 ms for a packet
|
|
if (nrf_rcv_pkt_time(200, sizeof(pkt), pkt) == 32) {
|
|
input = poem_identifyPacket(pkt);
|
|
if (input == BTN_NONE)
|
|
input = getInput();
|
|
}
|
|
else {
|
|
input = getInput();
|
|
}
|
|
return input;
|
|
}
|
|
|
|
|
|
/**
|
|
* Displays a small description of the game.
|
|
*/
|
|
static void poem_printUsage(void) {
|
|
// show usage
|
|
int dy = 0;
|
|
lcdFill(0);
|
|
DoString(0, dy, "Sortiere die Verse "); dy += POEM_FONT_HEIGHT;
|
|
DoString(0, dy, "in die richtige "); dy += POEM_FONT_HEIGHT;
|
|
DoString(0, dy, "Reihenfolge! Der "); dy += POEM_FONT_HEIGHT;
|
|
DoString(0, dy, "Knopf ist ein Joy- "); dy += POEM_FONT_HEIGHT;
|
|
DoString(0, dy, "stick. Waehle einen"); dy += POEM_FONT_HEIGHT;
|
|
DoString(0, dy, "Vers mit OBEN oder "); dy += POEM_FONT_HEIGHT;
|
|
DoString(0, dy, "UNTEN. Verschiebe "); dy += POEM_FONT_HEIGHT;
|
|
DoString(0, dy, "ihn per FEUERTASTE."); dy += POEM_FONT_HEIGHT;
|
|
lcdDisplay();
|
|
}
|
|
|
|
|
|
/**
|
|
* Initializes the wireless stuff.
|
|
*/
|
|
static void poem_initRadio(void) {
|
|
nrf_init();
|
|
static struct NRF_CFG config = {
|
|
.channel = 81,
|
|
.txmac = "\x1\x2\x3\x2\x1",
|
|
.nrmacs = 1,
|
|
.mac0 = "\x1\x2\x3\x2\x1",
|
|
.maclen = "\x20",
|
|
};
|
|
nrf_config_set(&config);
|
|
delayms(50);
|
|
}
|
|
|
|
|
|
/**
|
|
* Turns on the backlight and switches to dark text on a light background.
|
|
*/
|
|
static void poem_turnOnBacklight(void) {
|
|
GLOBAL(daytrig) = 255;
|
|
GLOBAL(daytrighyst) = 50;
|
|
GLOBAL(dayinvert) = 0;
|
|
GLOBAL(lcdinvert) = 1;
|
|
backlightSetBrightness(100);
|
|
lcdSetInvert(1);
|
|
lcdFill(0);
|
|
lcdDisplay();
|
|
}
|
|
|
|
|
|
/**
|
|
* Turns off the backlight and switches to light text on a dark background.
|
|
*/
|
|
static void poem_turnOffBacklight(void) {
|
|
GLOBAL(daytrig) = 0;
|
|
GLOBAL(daytrighyst) = 50;
|
|
GLOBAL(dayinvert) = 0;
|
|
GLOBAL(lcdinvert) = 0;
|
|
backlightSetBrightness(0);
|
|
lcdSetInvert(0);
|
|
lcdFill(0);
|
|
lcdDisplay();
|
|
}
|
|
|
|
|
|
/**
|
|
* Highlights the specified item by drawing a bounding box around it (to
|
|
* indicate a selection) or by inverting its representation (dragging).
|
|
* @param bIsDragging Whether the item is just selected or about to be dragged.
|
|
* @param nStartY The (absolute) start offset (in pixels) of the item.
|
|
* @param nStopY The (absolute) stop offset (in pixels) of the item.
|
|
* @param nScroll The vertical scrolling offset.
|
|
*/
|
|
static void poem_hightlightSelectedItem(unsigned int const bIsDragging,
|
|
int nStartY, int const nStopY, int const nScroll) {
|
|
// invert or draw a bounding box around the selected verse
|
|
if (bIsDragging) {
|
|
// dragging mode: invert the to be dragged item
|
|
for (int y = nStartY; y < nStopY; ++y) {
|
|
for (int x = 0; x < RESX; ++x) {
|
|
lcdSetPixel(x, y - nScroll, !lcdGetPixel(x, y - nScroll));
|
|
}
|
|
}
|
|
} else {
|
|
// selection mode: draw a border around the selected item
|
|
for (int x = 0; x < RESX; ++x) {
|
|
lcdSetPixel(x, nStartY - nScroll, 1);
|
|
lcdSetPixel(x, nStopY - nScroll, 1);
|
|
}
|
|
for (int y = nStartY; y < nStopY; ++y) {
|
|
lcdSetPixel(0, y - nScroll, 1);
|
|
lcdSetPixel(RESX - 1, y - nScroll, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Informs the master device that the player has accomplished the task and
|
|
* blocks as long as there are no "standby" or "wakeup" packets.
|
|
*/
|
|
static void poem_sendSuccessMessage(packet_type_t pktWinner) {
|
|
// send our winner information packet
|
|
static uint8_t pkt[32];
|
|
|
|
while (1) {
|
|
memcpy(pkt, poem_gPackets[pktWinner], sizeof(pkt));
|
|
nrf_snd_pkt_crc(sizeof(pkt), pkt);
|
|
// wait between 100 and 500 ms (including a potential 200 ms timeout of
|
|
// poem_getInputNonBlocking) to prevent polluting the channel with
|
|
// winner packets
|
|
delayms(100 + (getRandom() % 200));
|
|
uint8_t input = poem_getInputNonBlocking();
|
|
if (input == BTN_STANDBY) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Starts a game where the user has to sort verses of a poem into the right
|
|
* order.
|
|
*/
|
|
void main_poem(void) {
|
|
packet_type_t pktWinner = POEM_ID;
|
|
|
|
// display initialization
|
|
font = &POEM_FONT;
|
|
|
|
// init wireless stuff
|
|
poem_initRadio();
|
|
poem_prepareLineWrappingMarkers();
|
|
|
|
poem_state_t state = POEM_STATE_STANDBY;
|
|
|
|
while (1) {
|
|
switch (state) {
|
|
case POEM_STATE_STANDBY:
|
|
poem_turnOffBacklight();
|
|
lcdFill(0);
|
|
DoInt(0, 0, pktWinner);
|
|
lcdDisplay();
|
|
poem_getInputBlocking(BTN_WAKEUP);
|
|
state = POEM_STATE_USAGE;
|
|
break;
|
|
|
|
case POEM_STATE_USAGE:
|
|
poem_turnOnBacklight();
|
|
poem_printUsage();
|
|
{
|
|
uint8_t input = poem_getInputBlocking(BTN_UP | BTN_DOWN |
|
|
BTN_LEFT | BTN_RIGHT | BTN_ENTER | BTN_STANDBY);
|
|
if (input == BTN_STANDBY) {
|
|
state = POEM_STATE_STANDBY;
|
|
}
|
|
else if (input != BTN_WAKEUP) {
|
|
state = POEM_STATE_PLAYING;
|
|
}
|
|
}
|
|
DoString(20,0, "bla");
|
|
lcdDisplay();
|
|
break;
|
|
|
|
case POEM_STATE_PLAYING:
|
|
{
|
|
// print the verses
|
|
poem_t *const pPoem = &g_poem_aPoems[getRandom() % POEM_COUNT];
|
|
poem_initPermutation(pPoem);
|
|
unsigned int nSelectedVerse = 0, nNextSelected = 0;
|
|
unsigned int bIsDragging = 0;
|
|
while (state == POEM_STATE_PLAYING) {
|
|
// Calculate position and size of the bounding box of the selected
|
|
// verse. Also, calculate a vertical scrolling offset to ensure
|
|
// that the selected verse is visible.
|
|
int nStartY = 0;
|
|
for (unsigned int i = 0; i < nSelectedVerse; ++i) {
|
|
unsigned int index = pPoem->nPermut[i];
|
|
nStartY += POEM_FONT_HEIGHT * pPoem->nLineCounts[index] + 3;
|
|
}
|
|
const int nStopY = 2 + nStartY + (POEM_FONT_HEIGHT
|
|
* pPoem->nLineCounts[pPoem->nPermut[nSelectedVerse]]);
|
|
int nScroll = nStopY >= RESY ? nStopY - RESY + 1 : 0;
|
|
// display verses
|
|
lcdFill(0);
|
|
int dy = 2;
|
|
for (unsigned int i = 0; i < POEM_VERSE_COUNT; ++i) {
|
|
unsigned int const index = pPoem->nPermut[i];
|
|
for (unsigned int j = 0; j < pPoem->nLineCounts[index]; ++j) {
|
|
poem_printLine(pPoem, index, j, dy - nScroll);
|
|
dy += POEM_FONT_HEIGHT;
|
|
}
|
|
dy += 3;
|
|
}
|
|
// draw a bounding box around the selected verse (or invert it)
|
|
poem_hightlightSelectedItem(bIsDragging, nStartY, nStopY, nScroll);
|
|
// flush display buffer
|
|
lcdDisplay();
|
|
|
|
// both query joystick and listen for "standby" packets;
|
|
switch (poem_getInputBlocking(BTN_UP | BTN_DOWN |
|
|
BTN_ENTER | BTN_STANDBY)) {
|
|
case BTN_ENTER:
|
|
bIsDragging = !bIsDragging;
|
|
if (!bIsDragging && pPoem->nPermut[0] < pPoem->nPermut[1]
|
|
&& pPoem->nPermut[1] < pPoem->nPermut[2]
|
|
&& pPoem->nPermut[2] < pPoem->nPermut[3]) {
|
|
state = POEM_STATE_WON;
|
|
}
|
|
break;
|
|
|
|
case BTN_UP:
|
|
nNextSelected = nSelectedVerse > 0 ?
|
|
nSelectedVerse - 1 : nSelectedVerse;
|
|
break;
|
|
|
|
case BTN_DOWN:
|
|
nNextSelected = nSelectedVerse < (POEM_VERSE_COUNT - 1) ?
|
|
nSelectedVerse + 1 : nSelectedVerse;
|
|
break;
|
|
|
|
case BTN_STANDBY:
|
|
state = POEM_STATE_STANDBY;
|
|
break;
|
|
}
|
|
|
|
|
|
if (nSelectedVerse != nNextSelected && bIsDragging) {
|
|
unsigned int temp = pPoem->nPermut[nSelectedVerse];
|
|
pPoem->nPermut[nSelectedVerse] = pPoem->nPermut[nNextSelected];
|
|
pPoem->nPermut[nNextSelected] = temp;
|
|
}
|
|
nSelectedVerse = nNextSelected;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case POEM_STATE_WON:
|
|
lcdFill(0);
|
|
DoString(22, 30, "Geschafft!");
|
|
lcdDisplay();
|
|
poem_sendSuccessMessage(pktWinner);
|
|
state = POEM_STATE_STANDBY;
|
|
break;
|
|
}
|
|
}
|
|
}
|