1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* solitaire --- Shows a pointless game, used in the Mandarin Candidate */
3
4 #if 0
5 static const char sccsid[] = "@(#)solitaire.cc 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /* Copyright (c) D. Bagley, 1999. */
10
11 /*
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * This module is based on Eric Lassauge's text3d and Timothy Budd's
25 * C++ program from 1990 contained in the book "An Introduction to
26 * Object Oriented Programming" Addison-Wesley Publishing 1991.
27 *
28 * Albert H. Morehead and Geoffrey Mott-Smith, The Complete Book of
29 * Solitaire and Patience Games, Grosset & Dunlap, New York, 1949.
30 *
31 * After I started this I found out about some nice related sites:
32 * http://www.delorite.com/store/ace
33 * http://wildsav.idv.uni-linz.ac.at/mfx/psol-cardsets/index.html
34 *
35 * Revision History:
36 * 01-Nov-2000: Allocation checks
37 * 17-Jan-2000: autoplay, trackmouse, resizing, release
38 * 10-Dec-1999: wanted to do some C++, may end up using GL but not for now.
39 *
40 */
41
42 #ifdef STANDALONE
43 #define MODE_solitaire
44 #define DEFAULTS "*delay: 2000000 \n" \
45 "*ncolors: 64 \n" \
46 "*mouse: False \n"
47
48 # define reshape_solitaire 0
49 # define free_solitaire 0
50 # define solitaire_handle_event 0
51 #define UNIFORM_COLORS
52 extern "C"
53 {
54 #include "xlockmore.h" /* from the xscreensaver distribution */
55 }
56 #else /* !STANDALONE */
57 #include "xlock.h" /* in xlockmore distribution */
58 #endif /* !STANDALONE */
59
60 #ifdef MODE_solitaire
61
62 /* Methods overridden in subclasses of class cardPile
63 Suit Alternate Deck Discard Deal
64 initialize X X
65 cleanup X
66 addCard X X X
67 display X
68 select X X X
69 canTake X X
70 */
71
72 #define DEF_TRACKMOUSE "False"
73
74 static Bool trackmouse;
75
76 #define MAXCOLORS 2
77 #define MAXSUITS 4
78 #define MAXRANK 13
79 #define MAXALTERNATEPILES 7
80 #define MAXPILES (MAXALTERNATEPILES+MAXSUITS+2)
81 #define OVERLAP (0.25)
82
83 enum Colors {col_black, col_red};
84 enum Suits {spade, diamond, club, heart};
85
86 #ifdef FR
87 // Ace => As, Jack => Valet,
88 // Queen = Reine (Dame), King = Roi, Joker = Joker
89 static const char *RankNames[] = {"", "A",
90 "2", "3", "4", "5", "6", "7", "8", "9", "10",
91 "V", "D", "R"};
92 #else
93 #ifdef NL
94 // Ace => Aas, Jack => Boer (Farmer),
95 // Queen = Vrouw (Lady), King = Heer (Gentleman), Joker = Joker
96 static const char *RankNames[] = {"", "A",
97 "2", "3", "4", "5", "6", "7", "8", "9", "10",
98 "B", "V", "H"};
99 #else
100 #ifdef RU
101 // Some may be approximations to Cyrillic
102 static const char *RankNames[] = {"", "T",
103 "2", "3", "4", "5", "6", "7", "8", "9", "10",
104 "B", "Q", "K"};
105 #else
106 static const char *RankNames[] = {"", "A",
107 "2", "3", "4", "5", "6", "7", "8", "9", "10",
108 "J", "Q", "K"};
109 #endif
110 #endif
111 #endif
112
int_round(double x)113 static inline int int_round(double x) { return int(x + 0.5); }
114
115 #ifdef DOFONT
116 // Does this really add anything?
117 extern XFontStruct *getFont(Display * display);
118 static XFontStruct *mode_font = None;
119 static int char_width[256];
120
121 static int
font_width(XFontStruct * font,char ch)122 font_width(XFontStruct * font, char ch)
123 {
124 int dummy;
125 XCharStruct xcs;
126
127 (void) XTextExtents(font, &ch, 1, &dummy, &dummy, &dummy, &xcs);
128 return xcs.width;
129 }
130 #endif
131
132 static void
drawSpade(ModeInfo * mi,int x,int y,int width,int height)133 drawSpade(ModeInfo * mi, int x, int y, int width, int height)
134 {
135 Display *display = MI_DISPLAY(mi);
136 Window window = MI_WINDOW(mi);
137 GC gc = MI_GC(mi);
138 XPoint polygon[4];
139
140 polygon[0].x = x + width / 2;
141 polygon[0].y = y;
142 polygon[1].x = short(float(-width) / 3.0);
143 polygon[1].y = height / 3;
144 polygon[2].x = short(float(width) / 3.0);
145 polygon[2].y = height / 3;
146 polygon[3].x = short(float(width) / 3.0) + 1;
147 polygon[3].y = -height / 3;
148 XFillPolygon(display, window, gc,
149 polygon, 4, Convex, CoordModePrevious);
150 XFillArc(display, window, gc,
151 x, y + height / 3, width / 2, height / 2, 0, 23040);
152 XFillArc(display, window, gc,
153 x + width / 2, y + height / 3, width / 2, height / 2, 0, 23040);
154 polygon[0].x = x + width / 2;
155 polygon[0].y = y + height / 2;
156 polygon[1].x = -width / 8;
157 polygon[1].y = height / 2;
158 polygon[2].x = width / 4;
159 polygon[2].y = 0;
160 XFillPolygon(display, window, gc,
161 polygon, 3, Convex, CoordModePrevious);
162 }
163
164 static void
drawDiamond(ModeInfo * mi,int x,int y,int width,int height)165 drawDiamond(ModeInfo * mi, int x, int y, int width, int height)
166 {
167 Display *display = MI_DISPLAY(mi);
168 Window window = MI_WINDOW(mi);
169 GC gc = MI_GC(mi);
170 XPoint polygon[4];
171
172 polygon[0].x = x + width / 2;
173 polygon[0].y = y;
174 polygon[1].x = -width / 2;
175 polygon[1].y = height / 2;
176 polygon[2].x = width / 2;
177 polygon[2].y = height / 2;
178 polygon[3].x = width / 2;
179 polygon[3].y = -height / 2;
180 XFillPolygon(display, window, gc,
181 polygon, 4, Convex, CoordModePrevious);
182 }
183
184 static void
drawClub(ModeInfo * mi,int x,int y,int width,int height)185 drawClub(ModeInfo * mi, int x, int y, int width, int height)
186 {
187 Display *display = MI_DISPLAY(mi);
188 Window window = MI_WINDOW(mi);
189 GC gc = MI_GC(mi);
190 XPoint polygon[3];
191
192 XFillArc(display, window, gc,
193 x, y + short(float(height) / 3.6), width / 2, height / 2, 0, 23040);
194 XFillArc(display, window, gc,
195 x + width / 2, y + short(float(height) / 3.6), width / 2, height / 2, 0, 23040);
196 XFillArc(display, window, gc,
197 x + width / 4, y, width / 2, height / 2, 0, 23040);
198 polygon[0].x = x + width / 2;
199 polygon[0].y = y + height / 2 - 2;
200 polygon[1].x = -width / 8 - 1;
201 polygon[1].y = height / 2 + 2;
202 polygon[2].x = width / 4;
203 polygon[2].y = 0;
204 XFillPolygon(display, window, gc,
205 polygon, 3, Convex, CoordModePrevious);
206 }
207
208 static void
drawHeart(ModeInfo * mi,int x,int y,int width,int height)209 drawHeart(ModeInfo * mi, int x, int y, int width, int height)
210 {
211 Display *display = MI_DISPLAY(mi);
212 Window window = MI_WINDOW(mi);
213 GC gc = MI_GC(mi);
214 XPoint polygon[4];
215
216 XFillArc(display, window, gc,
217 x + 1, y, width / 2, height / 2, 0, 23040);
218 XFillArc(display, window, gc,
219 x + width / 2 - 1, y, width / 2, height / 2, 0, 23040);
220 polygon[0].x = x + width / 2;
221 polygon[0].y = y + short(float(height) / 4.1);
222 polygon[1].x = short(float(-width) / 2.7);
223 polygon[1].y = short(float(height) / 4.1);
224 polygon[2].x = short(float(width) / 2.7);
225 polygon[2].y = short(float(height) / 2.05);
226 polygon[3].x = short(float(width) / 2.7);
227 polygon[3].y = short(float(-height) / 2.05);
228 XFillPolygon(display, window, gc,
229 polygon, 4, Convex, CoordModePrevious);
230 }
231
232 void
drawSuit(ModeInfo * mi,Suits suit,int x,int y,int width,int height)233 drawSuit(ModeInfo * mi, Suits suit, int x, int y, int width, int height)
234 {
235 switch (suit) {
236 case spade:
237 drawSpade(mi, x, y, width, height);
238 break;
239 case diamond:
240 drawDiamond(mi, x, y, width, height);
241 break;
242 case club:
243 drawClub(mi, x, y, width, height);
244 break;
245 case heart:
246 drawHeart(mi, x, y, width, height);
247 break;
248 }
249 }
250
251 //card.h
252 class Card
253 {
254 private:
255 Suits suit;
256 int rank;
257 public:
258 Card(Suits suit, int rank);
259 Suits whichSuit();
260 int whichRank();
261 Colors whichColor();
262 };
Card(Suits a_suit,int a_rank)263 inline Card::Card(Suits a_suit, int a_rank) { this->suit = a_suit; this->rank = a_rank;}
whichSuit()264 inline Suits Card::whichSuit() { return this->suit;}
whichRank()265 inline int Card::whichRank() { return this->rank;}
whichColor()266 inline Colors Card::whichColor() { return ((whichSuit() % MAXCOLORS) ? col_red : col_black);}
267
268
269 //cardview.h
270 class CardView
271 {
272 private:
273 ModeInfo *mi;
274 Card * card;
275 Bool faceUp;
276 int locationX, locationY;
277 public:
278 CardView(ModeInfo * mi, Card * card);
279 CardView(ModeInfo *mi, Suits suit, int rank);
280 Card * thisCard();
281 void draw(int pileCount);
282 void erase();
283 Bool isFaceUp();
284 void flip();
285 Bool includes(int, int); // mouse interaction
286 int x();
287 int y();
288 int width();
289 int height();
290 void moveTo(int, int);
291 };
292
thisCard()293 inline Card* CardView::thisCard() { return card; }
isFaceUp()294 inline Bool CardView::isFaceUp() { return faceUp; }
flip()295 inline void CardView::flip() { faceUp = !faceUp; }
x()296 inline int CardView::x() { return locationX; }
y()297 inline int CardView::y() { return locationY; }
moveTo(int lx,int ly)298 inline void CardView::moveTo(int lx, int ly) { locationX = lx; locationY = ly; }
299
300 //cardview.cc
CardView(ModeInfo * a_mi,Card * a_card)301 CardView::CardView(ModeInfo * a_mi, Card * a_card)
302 {
303 this->mi = a_mi;
304 this->card = a_card;
305 faceUp = False;
306 locationX = locationY = 0;
307 }
308
CardView(ModeInfo * a_mi,Suits suit,int rank)309 CardView::CardView(ModeInfo * a_mi, Suits suit, int rank)
310 {
311 this->mi = a_mi;
312 if ((this->card = new Card(suit, rank)) == NULL) {
313 return;
314 }
315 faceUp = False;
316 locationX = locationY = 0;
317 }
318
draw(int pileCount)319 void CardView::draw(int pileCount)
320 {
321 Display * display = MI_DISPLAY(mi);
322 Window window = MI_WINDOW(mi);
323 GC gc = MI_GC(mi);
324 unsigned long red_pixel = (MI_NPIXELS(mi) > 2) ? MI_PIXEL(mi,0) : MI_BLACK_PIXEL(mi);
325 unsigned long cyan_pixel = (MI_NPIXELS(mi) > 2) ? MI_PIXEL(mi,MI_NPIXELS(mi) / 2) : MI_WHITE_PIXEL(mi);
326
327 if (isFaceUp()) {
328 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
329 XFillRectangle(display, window, gc, x(), y(), width(), height());
330 if (card->whichColor() == col_red) {
331 XSetForeground(display, gc, red_pixel);
332 } else {
333 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
334 }
335 if (width() > 16 && height() > 39) {
336 #ifdef CENTERLABEL
337 XDrawString(display, window, gc,
338 x() + width() / 2 - strlen(RankNames[card->whichRank()]) * 8,
339 y() + int_round(height() * 0.40),
340 (char *) RankNames[card->whichRank()], strlen(RankNames[card->whichRank()]));
341 #else
342 XDrawString(display, window, gc,
343 x() + 10 - strlen(RankNames[card->whichRank()]) * 8 + width() / 8,
344 y() + 25,
345 (char *) RankNames[card->whichRank()], strlen(RankNames[card->whichRank()]));
346 #endif
347 }
348 #ifdef SUITNAMES
349 const char *SuitNames[] = {"Spade", "Diamond", "Club", "Heart"};
350 XDrawString(display, window, gc, x() + 0.2, y() + int_round(height() * 0.8),
351 (char *) SuitNames[card->whichSuit()], strlen(SuitNames[card->whichSuit()]));
352 #endif
353 #ifdef CENTERLABEL
354 drawSuit(mi, card->whichSuit(),
355 x() + int_round(width() * 0.35), y() + int_round(height() * 0.55),
356 int_round(0.3 * width()), int_round(0.3 * height()));
357 #else
358 if (width() > 16 && height() > 39) {
359 drawSuit(mi, card->whichSuit(),
360 x() + 5, y() + 30,
361 int_round(0.3 * width()), int_round(0.3 * height()));
362 } else {
363 drawSuit(mi, card->whichSuit(),
364 x() + 2, y() + 2,
365 int_round(0.3 * width()), int_round(0.3 * height()));
366 }
367 #endif
368 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
369 XDrawLine(display, window, gc,
370 x() + 1, y() + 1, x() + width() - 2, y() + 1);
371 XDrawLine(display, window, gc,
372 x() + width() - 2, y() + height() - 2,
373 x() + 1, y() + height() - 2);
374 XDrawLine(display, window, gc,
375 x() + 1, y() + height() - 2, x() + 1, y() + 1);
376 XDrawLine(display, window, gc,
377 x() + width() - 2, y() + 1,
378 x() + width() - 2, y() + height() - 2);
379 } else {
380 int n, s, e;
381 int modCount = pileCount % 2; // shake it up a bit
382
383 XSetForeground(display, gc, cyan_pixel);
384 XFillRectangle(display, window, gc,
385 x(), y(), width(), height());
386 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
387 n = x() + int_round(int_round(width() * 0.3)) + modCount;
388 s = y() + int_round(height() * 0.1);
389 e = y() + int_round(height() * 0.9) - 1;
390 XDrawLine(display, window, gc,
391 n, s, n, e);
392 n = x() + int_round(width() * 0.7) - 1 + modCount;
393 XDrawLine(display, window, gc,
394 n, s, n, e);
395 n = y() + int_round(height() * 0.3) + modCount;
396 s = x() + int_round(height() * 0.1);
397 e = x() + int_round(width() * 0.9) - 1;
398 XDrawLine(display, window, gc,
399 s, n, e, n);
400 n = y() + int_round(height() * 0.7) - 1 + modCount;
401 XDrawLine(display, window, gc,
402 s, n, e, n);
403 }
404 // Shadow
405 #if 1
406 XDrawLine(display, window, gc,
407 x() - 1, y() - 1 , x() + width(), y() - 1);
408 XDrawLine(display, window, gc,
409 x() - 1, y() - 1, x() - 1, y() + height());
410 #else
411 XDrawLine(display, window, gc,
412 x() + 1, y() + height(), x() + width(), y() + height());
413 XDrawLine(display, window, gc,
414 x() + width(), y() + 1, x() + width(), y() + height());
415 #endif
416 }
417
erase()418 void CardView::erase()
419 {
420 Display * display = MI_DISPLAY(mi);
421 Window window = MI_WINDOW(mi);
422 GC gc = MI_GC(mi);
423
424 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
425 XFillRectangle(display, window, gc,
426 x(), y(), width(), height());
427 }
428
429 //pile.h
includes(int a,int b)430 Bool CardView::includes(int a, int b)
431 {
432 return (a >= x() && (a <= x() + width()) &&
433 b >= y() && (b <= y() + height()));
434 }
435
436 class CardLink : public CardView
437 {
438 public:
439 CardLink(ModeInfo * mi, Suits suit, int rank);
440 CardLink(ModeInfo * mi, Card * card);
441 CardLink * nextCard();
442 void setLink(CardLink * card);
443
444 private:
445 CardLink * link;
446 };
447
CardLink(ModeInfo * a_mi,Suits suit,int rank)448 inline CardLink::CardLink(ModeInfo *a_mi, Suits suit, int rank) : CardView(a_mi, suit, rank) { ; }
CardLink(ModeInfo * a_mi,Card * a_card)449 inline CardLink::CardLink(ModeInfo *a_mi, Card * a_card) : CardView(a_mi, a_card) { ; }
nextCard()450 inline CardLink * CardLink::nextCard() { return link; }
setLink(CardLink * a_card)451 inline void CardLink::setLink(CardLink * a_card) { link = a_card; }
452
453 class CardPile
454 {
455 public:
456 CardPile(ModeInfo *);
~CardPile()457 virtual ~CardPile() { ; }
458
459 virtual void updateLocation(ModeInfo *);
460 virtual void addCard(CardLink *);
461 virtual Bool canTake(Card *);
462 Bool contains(int, int); // mouse interaction
463 virtual void displayPile();
464 virtual Bool initialize();
465 virtual void cleanup();
466 CardLink * removeCard();
467 virtual Bool select(int, int); // mouse interaction
468 virtual Bool select(Bool); // generator
469 int pileCount();
470
471 protected:
472 int x, y;
473 ModeInfo * mi;
474 CardLink *top;
475 };
476
477 #define nilLink (CardLink *) 0
478
CardPile(ModeInfo * a_mi)479 inline CardPile::CardPile(ModeInfo * a_mi) { this->mi = a_mi; top = nilLink; }
480
481 class DealPile : public CardPile
482 {
483 public:
484 DealPile(ModeInfo *);
485 virtual void cleanup();
486 Bool shuffle(CardPile *);
487 };
DealPile(ModeInfo * a_mi)488 inline DealPile::DealPile(ModeInfo * a_mi) : CardPile(a_mi) { ; }
489
490 class SuitPile : public CardPile
491 {
492 public:
SuitPile(ModeInfo * a_mi,int s)493 SuitPile(ModeInfo * a_mi, int s) : CardPile(a_mi) { suit = s; }
494 virtual void updateLocation(ModeInfo *);
495 virtual Bool canTake(Card *);
496 private:
497 int suit;
498 };
499
500 class AlternatePile : public CardPile
501 {
502 public:
AlternatePile(ModeInfo * a_mi,int p)503 AlternatePile(ModeInfo * a_mi, int p) : CardPile(a_mi) { pile = p; }
504 virtual void updateLocation(ModeInfo *);
505 virtual void addCard(CardLink *);
506 virtual Bool canTake(Card *);
507 void copyBuild(CardLink *, CardPile *);
508 virtual void displayPile();
509 virtual Bool select(int, int);
510 virtual Bool select(Bool);
511 virtual Bool initialize();
512 private:
513 int pile;
514 };
515
516 class DeckPile : public CardPile
517 {
518 public:
DeckPile(ModeInfo * a_mi)519 DeckPile(ModeInfo * a_mi) : CardPile(a_mi) { ; }
520 virtual void updateLocation(ModeInfo *);
521 virtual void addCard(CardLink *);
522 virtual Bool initialize();
523 virtual Bool select(int, int);
524 virtual Bool select(Bool);
525 };
526
527 class DiscardPile : public CardPile
528 {
529 public:
DiscardPile(ModeInfo * a_mi)530 DiscardPile(ModeInfo * a_mi) : CardPile(a_mi) { ; }
531 virtual void updateLocation(ModeInfo *);
532 virtual void addCard(CardLink *);
533 virtual Bool select(int, int);
534 virtual Bool select(Bool);
535 };
536
537 //game.h
538 class GameTable
539 {
540 public:
541 GameTable(ModeInfo *);
542 ~GameTable();
543 Bool newGame(ModeInfo *);
544 Bool suitCanAdd(Card *);
545 CardPile * suitAddPile(Card *);
546 Bool alternateCanAdd(Card *);
547 CardPile * alternateAddPile(Card *);
548 void Resize(ModeInfo *);
549 void Draw(ModeInfo *);
550 void Redraw(ModeInfo *);
551 Bool HandleMouse(ModeInfo *);
552 Bool HandleGenerate();
553
554 DealPile *dealPile;
555
556 CardPile *deckPile;
557 CardPile *discardPile;
558 protected:
559 CardPile * allPiles[MAXALTERNATEPILES + MAXSUITS + 2];
560 CardPile * suitPiles[MAXSUITS];
561 CardPile * alternatePiles[MAXALTERNATEPILES];
562 };
563
564 // pile.cc
565
566 typedef struct {
567 Bool painted;
568 GameTable * game;
569 int width, height, cardwidth, cardheight;
570 int showend;
571 #ifdef DOFONT
572 int fontascent, fontheight;
573 #endif
574 } solitairestruct;
575
576 static solitairestruct *solitaire = (solitairestruct *) NULL;
577
width()578 int CardView::width()
579 {
580 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
581
582 return bp->cardwidth;
583 }
584
height()585 int CardView::height()
586 {
587 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
588
589 return bp->cardheight;
590 }
591
addCard(CardLink * card)592 void CardPile::addCard(CardLink * card)
593 {
594 if (card != nilLink) {
595 card->setLink(top);
596 top = card;
597 top->moveTo(x, y);
598 }
599 }
600
updateLocation(ModeInfo * a_mi)601 void CardPile::updateLocation(ModeInfo * a_mi)
602 {
603 ;
604 }
605
canTake(Card * card)606 Bool CardPile::canTake(Card * card)
607 {
608 return False; // from virtual, card unused
609 }
610
contains(int a,int b)611 Bool CardPile::contains(int a, int b)
612 {
613 for (CardLink *p = top; p!= nilLink; p = p->nextCard())
614 if (p->includes(a, b))
615 return True;
616 return False;
617 }
618
pileCount()619 int CardPile::pileCount()
620 {
621 int number = 0;
622 for (CardLink *p = top; p!= nilLink; p = p->nextCard())
623 number++;
624 return number;
625 }
626
displayPile()627 void CardPile::displayPile()
628 {
629 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
630 Display * display = MI_DISPLAY(mi);
631 Window window = MI_WINDOW(mi);
632 GC gc = MI_GC(mi);
633
634 if (top == nilLink) {
635 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
636 XFillRectangle(display, window, gc,
637 x, y, bp->cardwidth, bp->cardheight);
638 } else {
639 top->draw(pileCount());
640 }
641 }
642
initialize()643 Bool CardPile::initialize()
644 {
645 top = nilLink;
646 return True;
647 }
648
cleanup()649 void CardPile::cleanup()
650 {
651 CardLink *p;
652
653 while (top != nilLink) {
654 p = top;
655 top = top->nextCard();
656 delete p;
657 }
658 }
659
removeCard()660 CardLink * CardPile::removeCard()
661 {
662 CardLink *p;
663
664 if (top == nilLink)
665 return nilLink;
666 p = top;
667 top = top->nextCard();
668 return p;
669 }
670
select(int a_x,int a_y)671 Bool CardPile::select(int a_x, int a_y)
672 {
673 // from virtual, a_x & a_y unused
674 return select(True);
675 }
676
select(Bool first)677 Bool CardPile::select(Bool first)
678 {
679 // from virtual, first unused
680 return False;
681 }
682
cleanup()683 void DealPile::cleanup()
684 {
685 CardLink *p;
686
687 while (top != nilLink) {
688 p = top;
689 top = top->nextCard();
690 delete p->thisCard();
691 delete p;
692 }
693 }
694
shuffle(CardPile * pile)695 Bool DealPile::shuffle(CardPile * pile)
696 {
697 CardLink *p, *q;
698 int max, limit, i;
699
700 // first see how many cards we have
701 for (max = 0, p = top; p != nilLink; p = p->nextCard()) {
702 max++;
703 if (p->isFaceUp())
704 p->flip();
705 }
706 // then pull them out, randomly, one at a time
707 for (; max > 0; max--) {
708 limit = (int) ((LRAND() >> 3) % max) + 1;
709 for ( i= 1, p = top; i <= limit; ) {
710 while (p->isFaceUp())
711 p = p->nextCard();
712 i++;
713 if (i <= limit)
714 p = p->nextCard();
715 }
716 if ((q = new CardLink(mi, p->thisCard())) == NULL) {
717 return False;
718 }
719 pile->addCard(q);
720 p->flip();
721 }
722 return True;
723 }
724
updateLocation(ModeInfo * a_mi)725 void DeckPile::updateLocation(ModeInfo * a_mi)
726 {
727 solitairestruct *bp = &solitaire[MI_SCREEN(a_mi)];
728
729 //set pile
730 x = int_round(((bp->cardwidth + 2.0 * MAXSUITS * bp->cardwidth *
731 (MAXALTERNATEPILES + 1.0)) / (2.0 * MAXALTERNATEPILES)) +
732 3 * bp->cardwidth / 4.0);
733 y = int_round(0.25 * bp->cardheight);
734
735 // set card
736 for (CardLink *p = top; p!= nilLink; p = p->nextCard()) {
737 p->moveTo(x, y);
738 }
739 }
740
initialize()741 Bool DeckPile::initialize()
742 {
743 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
744
745 CardPile::initialize();
746 if (!bp->game->dealPile->shuffle(this))
747 return False;
748 return True;
749 }
750
addCard(CardLink * c)751 void DeckPile::addCard(CardLink *c)
752 {
753 if (c->isFaceUp())
754 c->flip();
755 CardPile::addCard(c);
756 }
757
select(int a_x,int a_y)758 Bool DeckPile::select(int a_x, int a_y)
759 {
760 // from virtual, a_x & a_y unused
761 return select(True);
762 }
763
764 // turn over a new card
select(Bool first)765 Bool DeckPile::select(Bool first)
766 {
767 // from virtual, first unused
768 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
769 CardLink *c;
770 Bool didSomething = False;
771
772 if (top != nilLink) {
773 c = removeCard(); // should not this be 3 at a time
774 if (c != nilLink)
775 (bp->game->discardPile)->addCard(c);
776 didSomething = True;
777 }
778 displayPile();
779 (bp->game->discardPile)->displayPile();
780 return didSomething;
781 }
782
updateLocation(ModeInfo * a_mi)783 void DiscardPile::updateLocation(ModeInfo * a_mi)
784 {
785 solitairestruct *bp = &solitaire[MI_SCREEN(a_mi)];
786
787 //set pile
788 x = int_round(((bp->cardwidth + 2.0 * MAXSUITS * bp->cardwidth *
789 (MAXALTERNATEPILES + 1.0)) / (2.0 * MAXALTERNATEPILES)) +
790 2 * bp->cardwidth);
791 y = int_round(0.25 * bp->cardheight);
792
793 // set card
794 for (CardLink *p = top; p!= nilLink; p = p->nextCard()) {
795 p->moveTo(x, y);
796 }
797 }
798
addCard(CardLink * c)799 void DiscardPile::addCard(CardLink *c)
800 {
801 if (!(c->isFaceUp()))
802 c->flip();
803 CardPile::addCard(c);
804 }
805
806 // play the current face card
select(int a_x,int a_y)807 Bool DiscardPile::select(int a_x, int a_y)
808 {
809 // from virtual, a_x & a_y unused
810 return select(True);
811 }
812
813 // play the current face card
select(Bool first)814 Bool DiscardPile::select(Bool first)
815 {
816 // from virtual, first unused
817 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
818 CardPile * pile;
819
820 if (top == nilLink)
821 return False;
822 // see if we can move it to a suit pile
823 if (bp->game->suitCanAdd(top->thisCard())) {
824 pile = bp->game->suitAddPile(top->thisCard());
825 pile->addCard(removeCard());
826 displayPile();
827 pile->displayPile();
828 return True;
829 }
830 if (bp->game->alternateCanAdd(top->thisCard())) {
831 pile = bp->game->alternateAddPile(top->thisCard());
832 pile->addCard(removeCard());
833 displayPile();
834 pile->displayPile();
835 return True;
836 }
837 return False;
838 }
839
updateLocation(ModeInfo * a_mi)840 void SuitPile::updateLocation(ModeInfo * a_mi)
841 {
842 solitairestruct *bp = &solitaire[MI_SCREEN(a_mi)];
843
844 //set pile
845 x = int_round(((bp->cardwidth + 2.0 * suit * bp->cardwidth *
846 (MAXALTERNATEPILES + 1.0)) / (2.0 * MAXALTERNATEPILES)) +
847 bp->cardwidth / 2.0);
848 y = int_round(0.25 * bp->cardheight);
849
850 // set card
851 for (CardLink *p = top; p!= nilLink; p = p->nextCard()) {
852 p->moveTo(x, y);
853 }
854 }
855
canTake(Card * card)856 Bool SuitPile::canTake(Card * card)
857 {
858 if (top == nilLink) { // empty so can take ace
859 if (card->whichRank() == 1)
860 return True;
861 return False;
862 }
863 if ((top->thisCard())->whichSuit() != card->whichSuit())
864 return False;
865 if (((top->thisCard())->whichRank() + 1) == card->whichRank())
866 return True;
867 return False;
868 }
869
updateLocation(ModeInfo * a_mi)870 void AlternatePile::updateLocation(ModeInfo * a_mi)
871 {
872 solitairestruct *bp = &solitaire[MI_SCREEN(a_mi)];
873 int ty;
874
875 //set pile
876 x = (int_round((bp->cardwidth + 2.0 * pile * bp->cardwidth *
877 (MAXALTERNATEPILES + 1.0)) / (2.0 * MAXALTERNATEPILES)));
878 y = int_round(1.5 * bp->cardheight);
879
880 CardLink *bf = nilLink;
881 // set card
882 for (CardLink *p = top; p!= nilLink; p = p->nextCard()) {
883 p->moveTo(x, y);
884 // find bottom faceup card
885 // not setup to work with STRANGE_LAYOUT
886 if (p->isFaceUp())
887 bf = p;
888 }
889 if (bf != nilLink) {
890 // ok but this is wrong. Since we only have a singly link
891 // we will do this slightly inefficiently...
892 ty = y;
893 while (bf != top) {
894 CardLink *sp;
895 for (sp = top; sp->nextCard() != bf; sp = sp->nextCard());
896 bf = sp;
897 ty += int_round(bp->cardheight * OVERLAP);
898 sp->moveTo(x, ty);
899 }
900 }
901 }
902
initialize()903 Bool AlternatePile::initialize()
904 {
905 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
906 int a_pile;
907
908 //put the right number of cards on the alternate
909 (void) CardPile::initialize();
910 for (a_pile = 0; a_pile <= this->pile; a_pile++)
911 addCard((bp->game->deckPile)->removeCard());
912 // flip the last one
913 if (top != nilLink) {
914 top->flip();
915 }
916 return True;
917 }
918
addCard(CardLink * card)919 void AlternatePile::addCard(CardLink * card)
920 {
921 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
922 int tx, ty;
923
924 if (top == nilLink)
925 CardPile::addCard(card);
926 else {
927 tx = top->x();
928 ty = top->y();
929
930 // figure out where to place the card
931 #ifdef STRANGE_LAYOUT
932 // This was the original logic... does not look right to me.
933 if (!(top->isFaceUp() && top->nextCard() != nilLink &&
934 (top->nextCard())->isFaceUp()))
935 #else
936 if (top->isFaceUp())
937 #endif
938 ty += int_round(bp->cardheight * OVERLAP);
939 CardPile::addCard(card);
940 top->moveTo(tx, ty);
941 }
942 }
943
canTake(Card * card)944 Bool AlternatePile::canTake(Card *card)
945 {
946 if (top == nilLink) { // can take only kings on an empty pile
947 if (card->whichRank() == MAXRANK) {
948 return True;
949 }
950 return False;
951 }
952 // see if it is face up, colors are different, and the number is legal
953 if ((top->thisCard())->whichColor() != card->whichColor() &&
954 ((top->thisCard())->whichRank() - 1) == card->whichRank()) {
955 return True;
956 }
957 return False;
958 }
959
copyBuild(CardLink * card,CardPile * a_pile)960 void AlternatePile::copyBuild(CardLink *card, CardPile * a_pile)
961 {
962 CardLink *tempCard;
963
964 top->erase();
965 tempCard = removeCard();
966 displayPile();
967 if (card != tempCard)
968 copyBuild(card, a_pile);
969 a_pile->addCard(tempCard);
970 a_pile->displayPile();
971 }
972
stackDisplay(CardLink * p)973 static void stackDisplay(CardLink *p)
974 {
975 if (p->nextCard())
976 stackDisplay(p->nextCard());
977 p->draw(0);
978 }
979
displayPile()980 void AlternatePile::displayPile()
981 {
982 // Zero or one cards, can not do any better
983 if (top == nilLink)
984 CardPile::displayPile();
985 else { // otherwise half display all the covered cards
986 stackDisplay(top);
987 }
988 }
989
select(int a_x,int a_y)990 Bool AlternatePile::select(int a_x, int a_y)
991 {
992 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
993 CardLink *c;
994
995 // no cards, do nothing
996 if (top == nilLink)
997 return False;
998
999 // if top card is not flipped, flip it now
1000 if (!top->isFaceUp()) {
1001 top->flip();
1002 top->draw(pileCount());
1003 return True;
1004 }
1005
1006 // if it was to top card, see if we can move it
1007 if (top->includes(a_x, a_y)) {
1008 // see if we ca move it to a suit pile
1009 if (bp->game->suitCanAdd(top->thisCard())) {
1010 copyBuild(top, bp->game->suitAddPile(top->thisCard()));
1011 return True;
1012 }
1013 // else see if we can move a alternate pile but only if it is not part of pile
1014 if (((top->nextCard() == nilLink) || !((top->nextCard())->isFaceUp())) &&
1015 bp->game->alternateCanAdd(top->thisCard())) {
1016 copyBuild(top, bp->game->alternateAddPile(top->thisCard()));
1017 return True;
1018 }
1019 }
1020
1021 // else see if we can move a pile
1022 for (c = top->nextCard(); c!= nilLink; c = c->nextCard())
1023 if (c->isFaceUp() && c->includes(a_x, a_y)) {
1024 if (bp->game->alternateCanAdd(c->thisCard())) {
1025 copyBuild(c, bp->game->alternateAddPile(c->thisCard()));
1026 }
1027 return True;
1028 }
1029 return False;
1030 }
1031
select(Bool first)1032 Bool AlternatePile::select(Bool first)
1033 {
1034 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
1035 CardLink *c;
1036
1037 // no cards, do nothing
1038 if (top == nilLink)
1039 return False;
1040
1041 // if top card is not flipped, flip it now
1042 if (!top->isFaceUp()) {
1043 top->flip();
1044 top->draw(pileCount());
1045 return True;
1046 }
1047 // see if we ca move it to a suit pile
1048 if (bp->game->suitCanAdd(top->thisCard())) {
1049 copyBuild(top, bp->game->suitAddPile(top->thisCard()));
1050 return True;
1051 }
1052
1053 // If all cards are not flipped it could lead to problems...
1054 if (first)
1055 return False;
1056
1057 // Other moves may be better but this is stupid
1058 // Bouncing may result if one allows to take away moves
1059 // find highest faceup card
1060 c = top;
1061 while (c->nextCard() != nilLink && (c->nextCard())->isFaceUp())
1062 c = c->nextCard();
1063
1064 // if not king see if it can be moved to leave a space (else it will bounce)
1065 if (((c->nextCard() != nilLink) ||
1066 ((c->thisCard())->whichRank() != MAXRANK)) &&
1067 bp->game->alternateCanAdd(c->thisCard())) {
1068 copyBuild(c, bp->game->alternateAddPile(c->thisCard()));
1069 return True;
1070 }
1071 return False;
1072 }
1073
GameTable(ModeInfo * mi)1074 GameTable::GameTable(ModeInfo *mi)
1075 {
1076 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
1077 int suit, rank, pile;
1078
1079 bp->width = MI_WIDTH(mi);
1080 bp->height = MI_HEIGHT(mi);
1081 bp->showend = 0;
1082 bp->cardwidth = bp->width / (MAXALTERNATEPILES + 1);
1083 bp->cardheight = bp->height / 5;
1084 // Create the original (unshuffled) deck (with no cards) ... dah daaah!
1085 if ((dealPile = new DealPile(mi)) == NULL) {
1086 return;
1087 }
1088 for (suit = 0; suit < MAXSUITS; suit++)
1089 for (rank = 1; rank <= MAXRANK; rank++) {
1090 CardLink * deal;
1091 // 52 pickup, creating new cards and creating links
1092 if ((deal = new CardLink(mi, Suits(suit), rank)) == NULL) {
1093 dealPile->cleanup();
1094 delete dealPile;
1095 return;
1096 }
1097 dealPile->addCard(deal);
1098 }
1099 // create 2 piles the deck and discard piles
1100 if ((allPiles[0] = deckPile = new DeckPile(mi)) == NULL) {
1101 dealPile->cleanup();
1102 delete dealPile;
1103 return;
1104 }
1105 deckPile->updateLocation(mi);
1106 if ((allPiles[1] = discardPile = new DiscardPile(mi)) == NULL) {
1107 dealPile->cleanup();
1108 delete dealPile;
1109 delete deckPile;
1110 return;
1111 }
1112 discardPile->updateLocation(mi);
1113
1114 // create suit piles
1115 for (suit = 0; suit < MAXSUITS; suit++) {
1116 if ((allPiles[suit + 2] = suitPiles[Suits(suit)] = new SuitPile(mi, suit)) == NULL) {
1117 delete this;
1118 return;
1119 }
1120 (suitPiles[Suits(suit)])->updateLocation(mi);
1121 }
1122
1123 // create alternate piles
1124 for (pile = 0; pile < MAXALTERNATEPILES; pile++) {
1125 if ((allPiles[pile + 2 + MAXSUITS] = alternatePiles[pile] =
1126 new AlternatePile(mi, pile)) == NULL) {
1127 delete this;
1128 return;
1129 }
1130 (alternatePiles[pile])->updateLocation(mi);
1131 }
1132 }
1133
~GameTable()1134 GameTable::~GameTable()
1135 {
1136 for (int pile = 0; pile < MAXPILES; pile++)
1137 if (allPiles[pile]) {
1138 allPiles[pile]->cleanup();
1139 delete allPiles[pile];
1140 }
1141 if (dealPile) {
1142 dealPile->cleanup();
1143 delete dealPile;
1144 }
1145 }
1146
Resize(ModeInfo * mi)1147 void GameTable::Resize(ModeInfo *mi)
1148 {
1149 solitairestruct *bp = &solitaire[MI_SCREEN(mi)];
1150 int suit, pile;
1151
1152 bp->width = MI_WIDTH(mi);
1153 bp->height = MI_HEIGHT(mi);
1154 bp->cardwidth = bp->width / (MAXALTERNATEPILES + 1);
1155 bp->cardheight = bp->height / 5;
1156 deckPile->updateLocation(mi);
1157 discardPile->updateLocation(mi);
1158
1159 // move suit piles
1160 for (suit = 0; suit < MAXSUITS; suit++) {
1161 (suitPiles[Suits(suit)])->updateLocation(mi);
1162 }
1163
1164 // move alternate piles
1165 for (pile = 0; pile < MAXALTERNATEPILES; pile++) {
1166 (alternatePiles[pile])->updateLocation(mi);
1167 }
1168 }
1169
newGame(ModeInfo * mi)1170 Bool GameTable::newGame(ModeInfo * mi)
1171 {
1172 int pile;
1173
1174 // initialize all the piles
1175 for (pile = 0; pile < MAXPILES; pile++)
1176 if (!allPiles[pile]->initialize())
1177 return False;
1178 // redraw the game window
1179 Redraw(mi);
1180 return True;
1181 }
1182
Draw(ModeInfo * mi)1183 void GameTable::Draw(ModeInfo * mi)
1184 {
1185 int pile;
1186
1187 // display the piles
1188 for (pile = 0; pile < MAXPILES; pile++)
1189 allPiles[pile]->displayPile();
1190 }
1191
1192 // this is where the smarts is/is not
Redraw(ModeInfo * mi)1193 void GameTable::Redraw(ModeInfo * mi)
1194 {
1195 //first clear the entire playing area
1196 MI_CLEARWINDOW(mi);
1197
1198 Draw(mi);
1199 }
1200
1201 // this is where the smarts is/is not
HandleMouse(ModeInfo * mi)1202 Bool GameTable::HandleMouse(ModeInfo * mi)
1203 {
1204 Window r, c;
1205 int cx, cy, rx, ry;
1206 unsigned int m;
1207 int pile;
1208
1209 (void) XQueryPointer(MI_DISPLAY(mi), MI_WINDOW(mi),
1210 &r, &c, &rx, &ry, &cx, &cy, &m);
1211
1212 if (cx <= 0 || cy <= 0 ||
1213 cx >= MI_WIDTH(mi) - 1 || cy >= MI_HEIGHT(mi) -1) {
1214 return HandleGenerate();
1215 }
1216
1217 for (pile = 0; pile < MAXPILES; pile++)
1218 if (allPiles[pile]->contains(cx, cy)) {
1219 (void) allPiles[pile]->select(cx, cy);
1220 return True;
1221 }
1222 return True;
1223 }
1224
1225 // if done right it looks smart...
HandleGenerate()1226 Bool GameTable::HandleGenerate()
1227 {
1228 int pile;
1229
1230 // Start with the biggest stacks... usually the last ones
1231 for (pile = MAXALTERNATEPILES - 1; pile >= 0; pile--)
1232 if (alternatePiles[pile]->select(True))
1233 return True;
1234 for (pile = MAXALTERNATEPILES - 1; pile >= 0; pile--)
1235 if (alternatePiles[pile]->select(False))
1236 return True;
1237 // Look for something to do in discard pile
1238 if (discardPile->select(True))
1239 return True;
1240
1241 // Get a new card or end it
1242 return (deckPile->select(True));
1243 }
1244
1245 // see if any of the suit piles can add a specific card
suitCanAdd(Card * card)1246 Bool GameTable::suitCanAdd(Card * card)
1247 {
1248 int suit;
1249
1250 for (suit = 0; suit < MAXSUITS; suit++)
1251 if (suitPiles[Suits(suit)]->canTake(card))
1252 return True;
1253 return False;
1254 }
1255
1256 // see if any of the alternate piles can add a specific card
alternateCanAdd(Card * card)1257 Bool GameTable::alternateCanAdd(Card * card)
1258 {
1259 int pile;
1260
1261 for (pile = 0; pile < MAXALTERNATEPILES; pile++)
1262 if (alternatePiles[pile]->canTake(card))
1263 return True;
1264 return False;
1265 }
1266
1267 // return which of the suit piles can add a card
suitAddPile(Card * card)1268 CardPile * GameTable::suitAddPile(Card * card)
1269 {
1270 int suit;
1271
1272 for (suit = 0; suit < MAXSUITS; suit++)
1273 if (suitPiles[Suits(suit)]->canTake(card))
1274 return suitPiles[Suits(suit)];
1275 (void) printf("suitAddPile\n");
1276 return (CardPile *) NULL; // Hopefully we can not get here
1277 }
1278
1279 // return which of the alternate piles can add a card
alternateAddPile(Card * card)1280 CardPile * GameTable::alternateAddPile(Card * card)
1281 {
1282 int pile;
1283
1284 for (pile = 0; pile < MAXPILES; pile++)
1285 if (alternatePiles[pile]->canTake(card))
1286 return alternatePiles[pile];
1287 (void) printf("alternateAddPile\n");
1288 return (CardPile *) NULL; // Hopefully we can not get here
1289 }
1290
1291 /* Yes, it's an ugly mix of 'C' and 'C++' functions */
1292 #ifdef STANDALONE
1293 static void draw_solitaire(ModeInfo * mi);
1294 #else
1295 extern "C" { void init_solitaire(ModeInfo * mi); }
1296 extern "C" { void draw_solitaire(ModeInfo * mi); }
1297 extern "C" { void change_solitaire(ModeInfo * mi); }
1298 extern "C" { void release_solitaire(ModeInfo * mi); }
1299 extern "C" { void refresh_solitaire(ModeInfo * mi); }
1300 #endif
1301 #ifndef DISABLE_INTERACTIVE
1302 static XrmOptionDescRec opts[] =
1303 {
1304 {(char *) "-trackmouse", (char *) ".solitaire.trackmouse", XrmoptionNoArg, (caddr_t) "on"},
1305 {(char *) "+trackmouse", (char *) ".solitaire.trackmouse", XrmoptionNoArg, (caddr_t) "off"}
1306 };
1307
1308 static argtype vars[] =
1309 {
1310 {(void *) & trackmouse, (char *) "trackmouse", (char *) "TrackMouse", (char *) DEF_TRACKMOUSE, t_Bool}
1311 };
1312
1313 static OptionStruct desc[] =
1314 {
1315 {(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the mouse"}
1316 };
1317
1318 ENTRYPOINT ModeSpecOpt solitaire_opts =
1319 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
1320 #else
1321 ModeSpecOpt solitaire_opts =
1322 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
1323 #endif
1324
1325 #ifdef USE_MODULES
1326 ModStruct solitaire_description =
1327 {(char *) "solitaire", (char *) "init_solitaire",
1328 (char *) "draw_solitaire", (char *) "release_solitaire",
1329 (char *) "refresh_solitaire", (char *) "init_solitaire",
1330 (char *) NULL, &solitaire_opts,
1331 2000000, 1, 1, 1, 64, 1.0, (char *) "",
1332 (char *) "Shows Klondike's game of solitaire", 0, NULL};
1333 #endif
1334
1335 /*
1336 *-----------------------------------------------------------------------------
1337 *-----------------------------------------------------------------------------
1338 * Xlock hooks.
1339 *-----------------------------------------------------------------------------
1340 *-----------------------------------------------------------------------------
1341 */
1342
1343 ENTRYPOINT void
refresh_solitaire(ModeInfo * mi)1344 refresh_solitaire(ModeInfo * mi)
1345 {
1346 solitairestruct *bp;
1347
1348 if (solitaire == NULL)
1349 return;
1350 bp = &solitaire[MI_SCREEN(mi)];
1351 if (!bp->game)
1352 return;
1353
1354 if (bp->painted) {
1355 bp->game->Redraw(mi);
1356 bp->painted = False;
1357 }
1358 }
1359
1360 /*
1361 *-----------------------------------------------------------------------------
1362 * Initialize solitaire. Called each time the window changes.
1363 *-----------------------------------------------------------------------------
1364 */
1365
1366 ENTRYPOINT void
init_solitaire(ModeInfo * mi)1367 init_solitaire(ModeInfo * mi)
1368 {
1369 solitairestruct *bp;
1370
1371 /*MI_INIT(mi, solitaire);*/
1372 if (solitaire == NULL) {
1373 if ((solitaire = (solitairestruct *) calloc(MI_NUM_SCREENS(mi),
1374 sizeof(solitairestruct))) == NULL)
1375 return;
1376 }
1377 bp = &solitaire[MI_SCREEN(mi)];
1378
1379 MI_CLEARWINDOW(mi);
1380 #ifdef DOFONT
1381 Display *display = MI_DISPLAY(mi);
1382 XGCValues gcv;
1383
1384 if (mode_font == None)
1385 mode_font = getFont(display);
1386 if (mode_font != None) {
1387 gcv.font = mode_font->fid;
1388 /*XSetFont(display, MI_GC(mi), mode_font->fid);*/
1389 gcv.graphics_exposures = False;
1390 gcv.foreground = MI_WHITE_PIXEL(mi);
1391 gcv.background = MI_BLACK_PIXEL(mi);
1392 if ((mp->gc = XCreateGC(display, MI_WINDOW(mi),
1393 GCForeground | GCBackground | GCGraphicsExposures | GCFont,
1394 &gcv)) == None) {
1395 return;
1396 }
1397 mp->ascent = mode_font->ascent;
1398 mp->height = font_height(mode_font);
1399 for (i = 0; i < 256; i++)
1400 char_width[i] = 8;
1401 }
1402 #endif
1403 if (bp->game) {
1404 if (bp->width != MI_WIDTH(mi) || bp->height != MI_HEIGHT(mi)) {
1405 /* Let us not be creative then... */
1406 bp->game->Resize(mi);
1407 bp->painted = True;
1408 refresh_solitaire(mi);
1409 return;
1410 }
1411 delete bp->game;
1412 }
1413 bp->painted = False;
1414 if ((bp->game = new GameTable(mi)) == NULL) {
1415 return;
1416 }
1417 if (!bp->game->newGame(mi)) {
1418 delete bp->game;
1419 }
1420 draw_solitaire(mi);
1421 }
1422
1423 /*
1424 *-----------------------------------------------------------------------------
1425 * Called by the mainline code periodically to update the display.
1426 *-----------------------------------------------------------------------------
1427 */
1428 ENTRYPOINT void
draw_solitaire(ModeInfo * mi)1429 draw_solitaire(ModeInfo * mi)
1430 {
1431 solitairestruct *bp;
1432
1433 if (solitaire == NULL)
1434 return;
1435 bp = &solitaire[MI_SCREEN(mi)];
1436 if (!bp->game)
1437 return;
1438
1439 MI_IS_DRAWN(mi) = True;
1440 bp->painted = True;
1441 if (bp->showend) {
1442 bp->showend++;
1443 if (bp->showend >= 10)
1444 init_solitaire(mi);
1445 } else if (trackmouse) {
1446 if (!bp->game->HandleMouse(mi)) {
1447 bp->showend++;
1448 }
1449 } else if (!bp->game->HandleGenerate()) {
1450 bp->showend++;
1451 }
1452 #ifdef STANDALONE
1453 bp->game->Draw(mi);
1454 #endif
1455 }
1456
1457 /*
1458 *-----------------------------------------------------------------------------
1459 * The display is being taken away from us. Free up malloc'ed
1460 * memory and X resources that we've alloc'ed. Only called
1461 * once, we must zap everything for every screen.
1462 *-----------------------------------------------------------------------------
1463 */
1464
1465 ENTRYPOINT void
release_solitaire(ModeInfo * mi)1466 release_solitaire(ModeInfo * mi)
1467 {
1468 if (solitaire != NULL) {
1469 for (int screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1470 solitairestruct *bp = &solitaire[screen];
1471
1472 if (bp->game)
1473 delete bp->game;
1474 }
1475 free(solitaire);
1476 solitaire = (solitairestruct *) NULL;
1477 }
1478 }
1479
1480 XSCREENSAVER_MODULE ("Solitaire", solitaire)
1481
1482 #endif /* MODE_solitaire */
1483