summaryrefslogtreecommitdiff
path: root/game.c
diff options
context:
space:
mode:
authorThomas Günther <tom@toms-cafe.de>2005-05-15 00:18:18 +0200
committerThomas Günther <tom@toms-cafe.de>2005-05-15 00:18:18 +0200
commit1b80a09e835a6cd68d4160f9799a7268e54a5b53 (patch)
treefa5f92848ed602216ed76ed84980921c9af95a07 /game.c
downloadvdr-plugin-spider-1b80a09e835a6cd68d4160f9799a7268e54a5b53.tar.gz
vdr-plugin-spider-1b80a09e835a6cd68d4160f9799a7268e54a5b53.tar.bz2
Initial versionv0.1.0
Diffstat (limited to 'game.c')
-rw-r--r--game.c403
1 files changed, 403 insertions, 0 deletions
diff --git a/game.c b/game.c
new file mode 100644
index 0000000..3e750ee
--- /dev/null
+++ b/game.c
@@ -0,0 +1,403 @@
+/*
+ * Spider-Arachnid: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include "game.h"
+#include "deck.h"
+#include "tableau.h"
+#include "heap.h"
+#include "setup.h"
+#include "bitmap.h"
+#include "i18n.h"
+#include <vdr/config.h>
+#include <vdr/osdbase.h>
+#include <vdr/osd.h>
+
+// Compatibility to older vdr versions
+#if VDRVERSNUM < 10307
+ #define tColor eDvbColor
+ #define DrawRectangle Fill
+ #define DrawBitmap SetBitmap
+ #define cOsdProvider cOsd
+ #define NewOsd OpenRaw
+ struct tArea { int x1, y1, x2, y2, bpp; };
+ #define SetAreas(a,n) Create(a->x1, a->y1,\
+ a->x2 - a->x1 + 1, a->y2 - a->y1 + 1,\
+ a->bpp, true)
+ #define clrGray50 clrBackground
+ #define Color GetColor
+#endif
+
+
+// Defintions for bitmaps
+const int cursorWidth = 16;
+const int cursorHeight = 22;
+const int cardWidth = 71;
+const int cardHeight = 96;
+
+const char* cursorName = "cursor";
+const char* coverName = "cover";
+const char* suitNames[] = { "herz", "karo", "pik", "kreuz" };
+const char* rankNames[] = { "ace", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten",
+ "jack", "queen", "king" };
+const int suitCount = sizeof(suitNames) / sizeof(*suitNames);
+const int rankCount = sizeof(rankNames) / sizeof(*rankNames);
+
+Bitmap* cursor = NULL;
+Bitmap* back = NULL;
+Bitmap* frame = NULL;
+Bitmap* cards[suitCount][rankCount];
+
+
+/** --- class SpiderGame --------------------------------------------------- **/
+
+/** Constructor */
+SpiderGame::SpiderGame(const SpiderSetup& setup, const char* confdir) :
+ cOsdObject(true), setup(setup), confdir(confdir)
+{
+ width = 504;
+ height = 360;
+ xPos = (720 - width) / 2;
+ yPos = (576 - height) / 2;
+ xDist = 1;
+ yDist = cardHeight / 6;
+ osd = NULL;
+ deck = NULL;
+ tableau = NULL;
+ currentPile = 0;
+ status = cursorOnPile;
+ info = new Bitmap(width * 2 / 3, 60);
+ infoText = NULL;
+}
+
+/** Destructor */
+SpiderGame::~SpiderGame()
+{
+ delete deck;
+ delete tableau;
+ delete info;
+ delete osd;
+ for (int s = 0; s < suitCount; ++s)
+ for (int r = 0; r < rankCount; ++r)
+ delete cards[s][r];
+ delete frame;
+ delete back;
+ delete cursor;
+ frame = back = cursor = NULL;
+}
+
+/** Display the game on the OSD */
+void SpiderGame::Show()
+{
+ osd = cOsdProvider::NewOsd(0, 0);
+ if (osd)
+ {
+ tArea areas[] = { xPos, yPos, xPos + width - 1, yPos + height - 1, 4 };
+ osd->SetAreas(areas, 1);
+ start();
+ paint();
+ }
+}
+
+/** Process user events */
+eOSState SpiderGame::ProcessKey(eKeys key)
+{
+ eOSState state = cOsdObject::ProcessKey(key);
+ if (state == osUnknown)
+ {
+ if (key == kBack)
+ return osEnd;
+ if (key == kBlue || (status == gameOver && key == kOk))
+ {
+ start();
+ status = cursorOnPile;
+ currentPile = 0;
+ }
+ else if (status == cursorOnPile)
+ {
+ switch (key)
+ {
+ case kLeft:
+ case kLeft|k_Repeat:
+ if (currentPile > 0)
+ --currentPile;
+ break;
+ case kRight:
+ case kRight|k_Repeat:
+ if (currentPile < tableau->piles.size() - 1)
+ ++currentPile;
+ break;
+ case kUp:
+ status = cursorOnPack;
+ break;
+ case kOk:
+ if (!tableau->piles[currentPile]->empty())
+ {
+ tableau->select(currentPile);
+ status = selectedPile;
+ }
+ break;
+ case kGreen:
+ tableau->backward();
+ break;
+ case kYellow:
+ tableau->forward();
+ break;
+ default:
+ return osContinue;
+ }
+ }
+ else if (status == selectedPile)
+ {
+ int selected = tableau->selected->selected();
+ int destination;
+ switch (key)
+ {
+ case kLeft:
+ destination = tableau->autoMoveLeft(currentPile);
+ if (destination >= 0)
+ {
+ currentPile = destination;
+ tableau->select(currentPile, selected);
+ }
+ break;
+ case kRight:
+ destination = tableau->autoMoveRight(currentPile);
+ if (destination >= 0)
+ {
+ currentPile = destination;
+ tableau->select(currentPile, selected);
+ }
+ break;
+ case kUp:
+ case kUp|k_Repeat:
+ tableau->selected->select(selected + 1);
+ if (key == kUp)
+ {
+ if (selected == deck->cardsInSuit)
+ {
+ tableau->remove();
+ status = cursorOnPile;
+ }
+ else if (selected == tableau->selected->selected())
+ infoText = tr("Only complete suits are allowed to remove");
+ }
+ break;
+ case kDown:
+ case kDown|k_Repeat:
+ if (selected > 1)
+ tableau->selected->select(selected - 1);
+ break;
+ case kOk:
+ tableau->unselect();
+ status = cursorOnPile;
+ break;
+ default:
+ return osContinue;
+ }
+ }
+ else if (status == cursorOnPack)
+ {
+ switch (key)
+ {
+ case kDown:
+ status = cursorOnPile;
+ currentPile = 0;
+ break;
+ case kOk:
+ if (tableau->pack->empty())
+ infoText = tr("No cards left");
+ else if (!tableau->noPileEmpty())
+ infoText = tr("Deal not allowed with empty piles");
+ else
+ tableau->deal();
+ break;
+ default:
+ return osContinue;
+ }
+ }
+ if (tableau->gameOver())
+ {
+ status = gameOver;
+ infoText = tr("Congratulations!\nPress OK to start a new game");
+ }
+ paint();
+ state = osContinue;
+ }
+ return state;
+}
+
+/** Start a new game */
+void SpiderGame::start()
+{
+ // Load bitmaps
+ if (cursor == NULL)
+ {
+ cursor = new Bitmap(cursorWidth, cursorHeight, confdir, cursorName);
+ back = new Bitmap(cardWidth, cardHeight, confdir, coverName);
+ frame = new Bitmap(cardWidth, cardHeight, clrWhite, clrGray50);
+
+ for (int s = 0; s < suitCount; ++s)
+ for (int r = 0; r < rankCount; ++r)
+ cards[s][r] = new Bitmap(cardWidth, cardHeight, confdir,
+ suitNames[s], rankNames[r]);
+ }
+
+ delete deck;
+ delete tableau;
+ deck = NULL;
+ tableau = NULL;
+
+ int deckCount, dealCount, pileCount;
+
+ if (setup.variation == SpiderSetup::Mini)
+ {
+ deckCount = 1;
+ dealCount = 4;
+ pileCount = 7;
+ }
+ else // normal variation
+ {
+ deckCount = 2;
+ dealCount = 5;
+ pileCount = 10;
+ xDist = -23;
+ }
+
+ if (pileCount > rankCount * suitCount * deckCount)
+ pileCount = rankCount * suitCount * deckCount;
+ int finalCount = suitCount * deckCount;
+ deck = new Deck(rankCount, suitCount, deckCount);
+ tableau = new Tableau(*deck, pileCount, finalCount, dealCount);
+}
+
+/** Paint all pieces of the game */
+void SpiderGame::paint()
+{
+ int x1 = xPos;
+ int x2 = xPos + width - 1;
+ int y1 = yPos;
+ int y2 = yPos + height - 1;
+ osd->DrawRectangle(x1, y1, x2, y2, clrGray50);
+ osd->DrawRectangle(x1, y1, x2, y1 + 1, clrRed);
+ osd->DrawRectangle(x1, y1, x1 + 1, y2, clrRed);
+ osd->DrawRectangle(x1, y2 - 1, x2, y2, clrRed);
+ osd->DrawRectangle(x2 - 1, y1, x2, y2, clrRed);
+
+ paintPack();
+
+ unsigned int f;
+ for (f = 0; f < tableau->finals.size(); ++f)
+ if (tableau->finals[f]->empty())
+ break;
+ unsigned int count = f;
+ for (f = tableau->finals.size(); f-- > count;)
+ paintFinal(f);
+ for (f = 0; f < count; ++f)
+ paintFinal(f);
+
+ unsigned int p;
+ for (p = tableau->piles.size(); p-- > currentPile + 1;)
+ paintPile(p);
+ for (p = 0; p <= currentPile; ++p)
+ paintPile(p);
+
+ if (infoText)
+ {
+ info->text(infoText);
+ osd->DrawBitmap(xPos + (width - info->Width()) / 2, yPos + 10, *info);
+ infoText = NULL;
+ }
+ osd->Flush();
+}
+
+/** Paint the pack */
+void SpiderGame::paintPack()
+{
+ int packX = xPos + 1;
+ int packY = yPos + 1;
+ if (tableau->pack->empty())
+ paintFrame(packX, packY);
+ else
+ paintBack(packX, packY);
+ if (status == cursorOnPack)
+ paintCursor(packX, packY);
+}
+
+/** Paint a final heap */
+void SpiderGame::paintFinal(unsigned int f)
+{
+ int offset = tableau->piles.size() - tableau->finals.size();
+ int finalX = xPos + 1 + (f + offset) * (cardWidth + xDist);
+ int finalY = yPos + 1;
+ if (tableau->finals[f]->empty())
+ paintFrame(finalX, finalY);
+ else
+ paintCard(finalX, finalY, tableau->finals[f]->top());
+}
+
+/** Paint a pile */
+void SpiderGame::paintPile(unsigned int p)
+{
+ int pileX = xPos + 1 + p * (cardWidth + xDist);
+ int pileY = yPos + 1 + cardHeight + 1;
+ paintFrame(pileX, pileY);
+
+ int count = tableau->piles[p]->count();
+ int closed = count - tableau->piles[p]->open();
+ int unselected = count - tableau->piles[p]->selected();
+ int dist = yDist;
+ if (pileY + (count + 1) * dist > yPos + height)
+ dist = (yPos + height - pileY) / (count + 1);
+
+ for (int c = 0; c < count; ++c, pileY += dist)
+ {
+ if (c == unselected)
+ pileY += dist;
+ if (c < closed)
+ paintBack(pileX, pileY);
+ else
+ paintCard(pileX, pileY, tableau->piles[p]->card(c));
+ }
+ if (count > 0)
+ pileY -= dist;
+ if ((status == cursorOnPile || status == selectedPile) && p == currentPile)
+ paintCursor(pileX, pileY);
+}
+
+/** Paint the cursor onto a card */
+void SpiderGame::paintCursor(int x, int y)
+{
+ int x0 = x + (cardWidth - cursorWidth) / 2;
+ int y0 = y + (cardHeight - cursorHeight) / 2;
+ tColor color = clrBlue;
+ if (status == selectedPile)
+ color = clrYellow;
+ for (x = 0; x < cursorWidth; ++x)
+ for (y = 0; y < cursorHeight; ++y)
+ if (cursor->Color(*cursor->Data(x, y)) != clrTransparent)
+ osd->DrawRectangle(x0 + x, y0 + y, x0 + x, y0 + y, color);
+}
+
+/** Paint an empty card frame */
+void SpiderGame::paintFrame(int x, int y)
+{
+ osd->DrawBitmap(x, y, *frame);
+}
+
+/** Paint a card back */
+void SpiderGame::paintBack(int x, int y)
+{
+ osd->DrawBitmap(x, y, *back);
+}
+
+/** Paint a card */
+void SpiderGame::paintCard(int x, int y, const Card& card)
+{
+ osd->DrawBitmap(x, y, *cards[card.suit][card.rank]);
+}