3e35566c97fe205afa3130ccec8ff0b0b075c99a
[sdk] / samples / games / cards / ruff / src / ruff.ec
1 import "ecere"
2
3 import "ai.ec"
4 import "server.ec"
5 import "scores.ec"
6 import "setup.ec"
7 import "bet.ec"
8 import "trump.ec"
9
10 enum Kind : byte { clubs, diamonds, hearts, spades, none = 0xFF };
11 enum Number : byte { _5, _7, _8, _9, _10, jack, queen, king, ace };
12
13 struct Card // class Card : uint16
14 {
15    Number number;
16    Kind kind;
17 } Card;
18
19 static String cardsNames[] =
20 {
21    ":ac.png", ":ad.png", ":ah.png", ":as.png",    ":2c.png", ":2d.png", ":2h.png", ":2s.png",    ":3c.png", ":3d.png", ":3h.png", ":3s.png",
22    ":4c.png", ":4d.png", ":4h.png", ":4s.png",    ":5c.png", ":5d.png", ":5h.png", ":5s.png",    ":6c.png", ":6d.png", ":6h.png", ":6s.png",
23    ":7c.png", ":7d.png", ":7h.png", ":7s.png",    ":8c.png", ":8d.png", ":8h.png", ":8s.png",    ":9c.png", ":9d.png", ":9h.png", ":9s.png",
24    ":10c.png", ":10d.png", ":10h.png", ":10s.png",":jc.png", ":jd.png", ":jh.png", ":js.png",    ":qc.png", ":qd.png", ":qh.png", ":qs.png",
25    ":kc.png", ":kd.png", ":kh.png", ":ks.png",    ":rb.png", ":rr.png"
26 };
27
28 static define CARD_WIDTH = 111;
29 static define CARD_HEIGHT = 150;
30
31 static define GAP = 38;
32
33 enum PlayerPosition : byte { bottom, left, top, right, none = 0xFF };
34
35 // For selectedCard
36 define None = 0xFF;
37
38 define RUFF = 0xFF;
39
40 enum PlayerType { local = 1, remotePlayer, ai };
41
42 struct Bet
43 {
44    PlayerPosition player;
45    // Range: 40-100, 0xFF: "ruff"
46    int howMuch;
47    Kind trump;
48 };
49
50 struct Round
51 {
52         PlayerPosition shuffle;
53         Bet bet;
54         int scores[2];
55 };
56
57 struct Player
58 {
59    RuffGame * game;
60    PlayerPosition id;
61    PlayerType type;
62    Socket socket;
63    Ruff ruff;
64
65    // Cards in hand
66    Card cards[11];
67    // Name of the player
68    char name[20];
69
70    // AI Player
71    bool left[4][9];
72    bool trumpLeft[4];
73    Kind trump;
74 };
75
76 define MAXROUNDS = 256;
77
78 define LT_RED  = Color { 255, 85, 85 };
79 define LT_BLUE = Color { 85, 85, 255 };
80
81 struct RuffGame
82 {
83    Player players[4];
84
85    Round rounds[MAXROUNDS];
86    int round;
87    int cardSet;   // Which of the 9 cards we're at in this round
88    PlayerPosition turn;  // Which player whose turn it is to play
89    PlayerPosition start; // Which player put the first card out of 4
90    bool betting;
91    bool gameStarted;
92
93    Card played[4];
94 };
95
96 define NUMCARDS = 36;
97
98 int RUFF_FirstValidCard(RuffGame * game, Player * player)
99 {
100         int c;
101         for(c=0; c<9; c++)
102                 if(RUFF_Legal(game, player, c))
103                         return c;
104    return 0;
105 }
106
107 enum MessageType : byte
108 {
109    S2C_WELCOME        = 1,
110    S2C_PLAYERINFO     = 2,
111    S2C_CARDPLAYED     = 3,
112    S2C_STARTGAME      = 4,
113    S2C_STOPGAME       = 5,
114    S2C_BET            = 6,
115    S2C_TRUMP          = 7,
116    S2C_ENDOFROUND     = 8,
117    S2C_REQBET         = 9,
118    S2C_REQTRUMP       = 10,
119    S2C_REQCARD        = 11,
120    S2C_REQACK         = 12,
121    S2C_NEWROUND       = 13,
122    S2C_STARTHAND      = 14,
123    C2S_PLAYERNAME     = 20,
124    C2S_PLACEBET       = 21,
125    C2S_CHOSETRUMP     = 22,
126    C2S_PLAYCARD       = 23,
127    C2S_ACK4CARDS      = 24
128 };
129
130 struct Message
131 {
132    uint size;
133    MessageType type;
134 };
135
136 // SERVER TO CLIENT ( ** SETUP ** )
137 struct S2CWelcome : Message
138 {
139    int id;
140 };
141
142 struct S2CPlayerInfo : Message
143 {
144    int id;
145    byte name[1];
146 };
147
148 struct S2CCardPlayed : Message
149 {
150    int id;
151    Kind kind;
152    Number number;
153 };
154
155 struct S2CBet : Message
156 {
157    int who;
158    int howMuch;
159 };
160
161 struct S2CTrump : Message
162 {
163    int trump;
164 };
165
166 struct S2CEndOfRound : Message
167 {
168    int score0, score1;
169 };
170
171 struct S2CReqAck : Message
172 {
173    int winner;
174    int scores0, scores1;
175 };
176
177 struct S2CNewRound : Message
178 {
179    int round;
180    int shuffle;
181    Card cards[9];
182 };
183
184 struct S2CStartHand : Message
185 {
186    int start;
187    int scores[2];
188 };
189
190 // CLIENT TO SERVER ( ** SETUP ** )
191
192 struct C2SPlayerName : Message
193 {
194    byte name[1];
195 };
196
197 struct C2SPlaceBet : Message
198 {
199    int bet;
200 };
201
202 struct C2SChoseTrump : Message
203 {
204    int trump;
205 };
206
207 struct C2SPlayCard : Message
208 {
209    int card;
210 };
211
212
213 // CLIENT TO SERVER
214 void Player_PlaceBet(Player player, int bet)
215 {
216    if(player.socket)
217    {
218       C2SPlaceBet placeBet { sizeof(C2SPlaceBet), C2S_PLACEBET, bet };
219       player.socket.Send(placeBet, sizeof(placeBet));
220    }
221    else
222       Server_PlaceBet(player.game, player, bet);
223 }
224
225 void Player_ChoseTrump(Player player, Kind trump)
226 {
227    if(player.socket)
228    {
229       C2SChoseTrump choseTrump { sizeof(C2SChoseTrump), C2S_CHOSETRUMP, trump };
230       player.socket.Send(choseTrump, sizeof(choseTrump));
231    }
232    else
233       Server_ChoseTrump(player.game, player, trump);
234 }
235
236 void Player_PlayCard(Player player, int card)
237 {
238    Ruff ruff = player.ruff;
239
240    ruff.selectedCard = None;
241    if(player.socket)
242    {
243       C2SPlayCard playCard { sizeof(C2SPlayCard), C2S_PLAYCARD, card };
244       player.socket.Send(playCard, sizeof(playCard));
245
246       player.cards[card].kind = none;
247    }
248    else
249       Server_PlayCard(player.game, player, card);
250 }
251
252 void Player_Ack4Cards(Player player, PlayerPosition winner, int scores0, int scores1)
253 {
254    Ruff ruff = player.ruff;
255    RuffGame * game = &ruff.game;
256
257    // ruff.waitingAck = false;
258
259    ruff.lastWinner = winner;
260    ruff.lastStart = game->start;
261    if(game->played[0].kind != none)
262    {
263       CopyBytes(ruff.lastPlayed,game->played, sizeof(Card) * 4);
264       FillBytes(game->played, None, sizeof(Card) * 4);
265    }
266
267    if(player.socket)
268    {
269       // Message msg { sizeof(Message), C2S_ACK4CARDS };
270       // player.socket.Send(, &msg, sizeof(msg));
271
272       game->rounds[game->round].scores[0] = scores0;
273       game->rounds[game->round].scores[1] = scores1;
274       ruff.Update(null);
275       ruff.scores.Update(null);
276    }
277 }
278
279 void Player_SetName(Player player, char * name)
280 {
281    Ruff ruff = player.ruff;
282    if(player.socket)
283    {
284       C2SPlayerName * playerName = (C2SPlayerName *)new byte[sizeof(C2SPlayerName) + strlen(name)];
285       playerName->type = C2S_PLAYERNAME;
286       playerName->size = sizeof(C2SPlayerName) + strlen(name);
287       strcpy(playerName->name, name);
288       player.socket.Send(playerName, playerName->size);
289       delete playerName;
290    }
291    else
292       Server_SetName(player.game, player, name);
293 }
294
295 // SERVER TO CLIENT : Informations
296 void Player_InformPlayerInfo(Player player, PlayerPosition who, char *name)
297 {
298    Ruff ruff = player.ruff;
299    RuffGame * game = &ruff.game;
300
301    strcpy(game->players[who].name, name);
302    ruff.Update(null);
303    ruff.scores.Update(null);
304
305    switch(player.type)
306    {
307       case remotePlayer:
308       {
309          if(player.socket)
310          {
311             S2CPlayerInfo * playerInfo = (S2CPlayerInfo *)new byte[sizeof(S2CPlayerInfo) + strlen(name)];
312             playerInfo->type = S2C_PLAYERINFO;
313             playerInfo->size = sizeof(S2CPlayerInfo) + strlen(name);
314             playerInfo->id = who;
315             strcpy(playerInfo->name, name);
316             player.socket.Send(playerInfo, playerInfo->size);
317             delete playerInfo;
318          }
319          break;
320       }
321    }
322 }
323
324 void Player_InformStartGame(Player player)
325 {
326    Ruff ruff = player.ruff;
327    RuffGame * game = &ruff.game;
328
329    int c;
330    for(c = 0; c<11; c++)
331       player.cards[c].kind = none;
332    for(c = 0; c<4; c++)
333       game->played[c].kind = none;
334
335    ruff.lastWinner = none;
336    ruff.lastStart = none;
337    ruff.lastPlayed[0].kind = ruff.lastPlayed[1].kind =
338    ruff.lastPlayed[2].kind = ruff.lastPlayed[3].kind = none;
339    game->gameStarted = true;
340
341    ruff.setup.EnableButtons();
342    ruff.Update(null);
343    ruff.scores.Update(null);
344
345    ruff.selectedCard = None;
346    game->round = 0;
347
348    switch(player.type)
349    {
350       case local:
351       {
352          ruff.playedPlayer = player.id;
353          break;
354       }
355       case remotePlayer:
356       {
357          Message startGame { sizeof(Message), S2C_STARTGAME };
358          player.socket.Send(startGame, sizeof(startGame));
359          break;
360       }
361    }
362    ruff.Activate();
363 }
364
365 void Player_InformStopGame(Player player)
366 {
367    Ruff ruff = player.ruff;
368    RuffGame * game = &ruff.game;
369
370    game->gameStarted = false;
371    ruff.trump.Destroy(0);
372    ruff.bet.Destroy(0);
373
374    ruff.setup.EnableButtons();
375    ruff.Update(null);
376    ruff.scores.Update(null);
377
378    switch(player.type)
379    {
380       case remotePlayer:
381       {
382          if(player.socket)
383          {
384             Message stopGame { sizeof(Message), S2C_STOPGAME };
385             player.socket.Send(stopGame, sizeof(stopGame));
386          }
387          break;
388       }
389    }
390 }
391
392 void Player_InformNewRound(Player player, int r, PlayerPosition shuffle, Card * cards)
393 {
394    Ruff ruff = player.ruff;
395    RuffGame * game = &ruff.game;
396
397    int c;
398    Round * round;
399    for(c = 0; c<9; c++)
400       player.cards[c] = cards[c];
401    game->round = r;
402    game->betting = true;
403
404    round = &game->rounds[game->round];
405    round->bet.howMuch = 0;
406    round->bet.trump = none;
407    round->bet.player = none;
408    round->shuffle = shuffle;
409    round->scores[0] = round->scores[1] = 0;
410
411    switch(player.type)
412    {
413       case local:
414       {
415          ruff.Update(null);
416          ruff.scores.Update(null);
417          break;
418       }
419       case ai:
420       {
421          AI_InformNewRound(player, r, shuffle, cards);
422          break;
423       }
424       case remotePlayer:
425       {
426          S2CNewRound newRound { sizeof(S2CNewRound), S2C_NEWROUND, r, shuffle };
427          CopyBytes(newRound.cards, cards, sizeof(newRound.cards));
428          player.socket.Send(newRound, sizeof(newRound));
429          break;
430       }
431    }
432 }
433
434 void Player_InformBet(Player player, PlayerPosition who, int howMuch)
435 {
436    Ruff ruff = player.ruff;
437    RuffGame * game = &ruff.game;
438    Round * round = &game->rounds[game->round];
439
440    switch(player.type)
441    {
442       case local:
443       {
444          if(howMuch)
445          {
446             round->bet.player = who;
447             round->bet.howMuch = howMuch;
448          }
449          ruff.Update(null);
450          ruff.scores.Update(null);
451          break;
452       }
453       case ai:
454       {
455          AI_InformBet(player, who, howMuch);
456          break;
457       }
458       case remotePlayer:
459       {
460          S2CBet bet { sizeof(S2CBet), S2C_BET, who, howMuch };
461          player.socket.Send(bet, sizeof(bet));
462          break;
463       }
464    }
465 }
466
467 void Player_InformTrump(Player player, Kind trump)
468 {
469    Ruff ruff = player.ruff;
470    RuffGame * game = &ruff.game;
471    Round * round = &game->rounds[game->round];
472    game->betting = false;
473    switch(player.type)
474    {
475       case local:
476       {
477          round->bet.trump = trump;
478          ruff.Update(null);
479          ruff.scores.Update(null);
480          break;
481       }
482       case ai:
483       {
484          AI_InformTrump(player, trump);
485          break;
486       }
487       case remotePlayer:
488       {
489          S2CTrump informTrump { sizeof(S2CTrump), S2C_TRUMP, trump };
490          player.socket.Send(informTrump, sizeof(informTrump));
491          break;
492       }
493    }
494 }
495
496 void Player_InformStartHand(Player player, PlayerPosition start)
497 {
498    Ruff ruff = player.ruff;
499    RuffGame * game = &ruff.game;
500
501    switch(player.type)
502    {
503       case local:
504       {
505          ruff.Update(null);
506          ruff.scores.Update(null);
507          game->start = start;
508          break;
509       }
510       case remotePlayer:
511       {
512          S2CStartHand startHand { sizeof(S2CStartHand), S2C_STARTHAND, start };
513          player.socket.Send(startHand, sizeof(startHand));
514          break;
515       }
516    }
517 }
518
519 void Player_InformCardPlayed(Player player, int who, Kind kind, Number number)
520 {
521    Ruff ruff = player.ruff;
522    RuffGame * game = &ruff.game;
523
524    switch(player.type)
525    {
526       case local:
527       {
528          game->played[who].kind = kind;
529          game->played[who].number = number;
530          ruff.Update(null);
531          ruff.scores.Update(null);
532          break;
533       }
534       case ai:
535       {
536          AI_InformCardPlayed(player, who, kind, number);
537          break;
538       }
539       case remotePlayer:
540       {
541          S2CCardPlayed cardPlayed { sizeof(S2CCardPlayed), S2C_CARDPLAYED, who, kind, number };
542          player.socket.Send(cardPlayed, sizeof(cardPlayed));
543          break;
544       }
545    }
546 }
547
548 void Player_InformEndOfRound(Player player, int score0, int score1)
549 {
550    Ruff ruff = player.ruff;
551    RuffGame * game = &ruff.game;
552    switch(player.type)
553    {
554       case local:
555       {
556          Round * round = &game->rounds[game->round];
557          round->scores[0] = score0;
558          round->scores[1] = score1;
559          break;
560       }
561       case ai:
562       {
563          AI_InformEndOfRound(player, score0, score1);
564          break;
565       }
566       case remotePlayer:
567       {
568          S2CEndOfRound endOfRound { sizeof(S2CEndOfRound), S2C_ENDOFROUND, score0, score1 };
569          player.socket.Send(endOfRound, sizeof(endOfRound));
570          break;
571       }
572    }
573    ruff.Update(null);
574    ruff.scores.Update(null);
575 }
576
577 // SERVER TO CLIENT : Requests
578 void Player_RequestBet(Player player)
579 {
580    Ruff ruff = player.ruff;
581    RuffGame * game = &ruff.game;
582
583    switch(player.type)
584    {
585       case local:
586       {
587          char temp[256];
588
589          game->turn = player.id;
590          ruff.playedPlayer = player.id;
591          ruff.selectedCard = None;
592
593          sprintf(temp, "Your bet, %s?", player.name);
594          ruff.bet.text = temp;
595          ruff.bet.visible = true;
596          ruff.bet.Create();
597          ruff.Update(null);
598          ruff.scores.Update(null);
599          break;
600       }
601       case ai:
602       {
603          AI_RequestBet(player);
604          break;
605       }
606       case remotePlayer:
607       {
608          Message reqBet { sizeof(Message), S2C_REQBET };
609          player.socket.Send(reqBet, sizeof(reqBet));
610          break;
611       }
612    }
613 }
614
615 void Player_RequestTrump(Player player)
616 {
617    Ruff ruff = player.ruff;
618
619    switch(player.type)
620    {
621       case local:
622       {
623          char temp[256];
624
625          ruff.playedPlayer = player.id;
626          ruff.selectedCard = None;
627
628          sprintf(temp, "Chose your trump, %s?", player.name);
629          ruff.trump.text = temp;
630          ruff.trump.Create();
631          ruff.Update(null);
632          ruff.scores.Update(null);
633          break;
634       }
635       case ai:
636          AI_RequestTrump(player);
637          break;
638       case remotePlayer:
639       {
640          Message reqTrump { sizeof(Message), S2C_REQTRUMP };
641          player.socket.Send(reqTrump, sizeof(reqTrump));
642          break;
643       }
644    }
645 }
646
647 void Player_RequestCard(Player player)
648 {
649    Ruff ruff = player.ruff;
650    RuffGame * game = &ruff.game;
651
652    switch(player.type)
653    {
654       case local:
655          ruff.playedPlayer = player.id;
656          game->turn = player.id;
657          ruff.selectedCard = RUFF_FirstValidCard(game, player);
658          ruff.Update(null);
659          ruff.scores.Update(null);
660          break;
661       case ai:
662          AI_RequestCard(player);
663          break;
664       case remotePlayer:
665       {
666          Message reqCard { sizeof(Message), S2C_REQCARD };
667          player.socket.Send(reqCard, sizeof(reqCard));
668          break;
669       }
670    }
671 }
672
673 void Player_Request4CardsAck(Player player, PlayerPosition winner, int scores0, int scores1)
674 {
675    Ruff ruff = player.ruff;
676    RuffGame * game = &ruff.game;
677
678    switch(player.type)
679    {
680       case local:
681          // ruff.waitingAck = true;
682          Player_Ack4Cards(player, winner, scores0, scores1);
683          break;
684       case ai:
685          // ruff.waitingAck = true;
686          break;
687       case remotePlayer:
688       {
689          S2CReqAck reqAck { sizeof(S2CReqAck), S2C_REQACK, winner, scores0, scores1 };
690          player.socket.Send(reqAck, sizeof(reqAck));
691          break;
692       }
693    }
694 }
695
696
697 class Ruff : Window
698 {
699    text = "The Ruff Card Game";
700    borderStyle = sizable;
701    hasMaximize = true, hasMinimize = true, hasClose = true;
702    anchor = { horz = -0.1, vert = -0.1 };
703    clientSize = { 926, 688 };
704    background = { 0, 128, 0 };
705
706    // State of the game
707    RuffGame game;
708
709    // Windows
710    Scores scores
711    {
712       master = this
713    };
714    Setup setup
715    {
716       master = this
717    };
718
719    BetDialog bet
720    {
721       parent = this,
722       font = FontResource { "Tahoma", 8.25f },
723       anchor = Anchor { horz = 25, vert = 55 },
724       autoCreate = false;
725       void NotifyDestroyed(Window window, DialogResult result)
726       {
727          Player * player = &game.players[playedPlayer];
728          if(game.gameStarted)
729             Player_PlaceBet(player, (int)result);
730       }
731    };
732
733    TrumpDialog trump
734    {
735       parent = this,
736       font = FontResource { "Tahoma", 8.25f },
737       autoCreate = false;
738       anchor = Anchor { horz = 25, vert = 55 };
739       void NotifyDestroyed(Window window, DialogResult result)
740       {
741          Player * player = &game.players[playedPlayer];
742          if(game.gameStarted)
743             Player_ChoseTrump(player, (Kind)result);
744       }
745    };
746
747    // Bitmaps
748    Bitmap bitmapCards[52];
749    Bitmap cardBack {};
750    font = FontResource { "Comic Sans MS Bold", 16 };
751
752    // Playing Interface
753    Card lastPlayed[4];
754    PlayerPosition playedPlayer;
755    PlayerPosition lastWinner;
756    PlayerPosition lastStart;
757    int selectedCard;
758    bool waitingAck;
759
760    // CLIENT INTERFACE
761    void OnRedraw(Surface surface)
762    {
763       Player * player = (playedPlayer != none) ? &game.players[playedPlayer] : null;
764       Round * round = &game.rounds[game.round];
765       PlayerPosition c;
766       static const Point playedPos[] = { { 461, 528 }, { 268, 372 }, { 461, 215 }, { 652, 372 } };
767       static const Point lastPlayedPos[] = { { 430, 497 }, { 238, 340 }, { 430, 184 }, { 621, 340 } };
768       static const Point namePos[] = { { 313, 585 }, { 156, 422 }, { 688, 254 }, { 844, 422 } };
769
770       if(game.gameStarted)
771       {
772          if(player)
773          {
774             int c;
775             // The player's hand
776             for(c=0; c<11; c++)
777             {
778                       if(player->cards[c].kind != none)
779                       {
780                   if(c != selectedCard)
781                      RUFF_DrawCard(surface, c * GAP + player->cards[c].kind * CARD_WIDTH, 20, &player->cards[c]);
782                       }
783             }
784
785             // The selected card
786             if(selectedCard != None && player->cards[selectedCard].kind != none)
787                RUFF_DrawCard(surface,
788                   selectedCard * GAP + player->cards[selectedCard].kind * CARD_WIDTH, 0,
789                   &player->cards[selectedCard]);
790          }
791
792          // This round's bet and trump
793          if(round->bet.howMuch)
794          {
795             surface.SetForeground((round->bet.player == playedPlayer) ? LT_RED : black);
796             surface.CenterTextf(868, 164, "%d",round->bet.howMuch);
797             if(round->bet.trump != none)
798             {
799                Card card;
800                card.kind = round->bet.trump;
801                card.number = ace;
802                RUFF_DrawCard(surface, 813, 0, &card);
803             }
804             surface.CenterTextf(868, 200, game.players[round->bet.player].name);
805          }
806
807          // 4 Cards Played
808          for(c = 0; c<4; c++)
809          {
810             if(lastPlayed[c].kind != none)
811                RUFF_DrawCard(surface, lastPlayedPos[c].x, lastPlayedPos[c].y, &lastPlayed[c]);
812
813             if(game.played[c].kind != none)
814                RUFF_DrawCard(surface, playedPos[c].x, playedPos[c].y, &game.played[c]);
815             else
816                RUFF_DrawCard(surface, playedPos[c].x, playedPos[c].y, null);
817
818             if(!game.betting && c == game.start)
819             {
820                surface.SetForeground(LT_RED);
821                surface.CenterTextf(playedPos[c].x + 10, playedPos[c].y + 50, "S");
822             }
823             if(c == lastWinner)
824             {
825                surface.SetForeground(LT_BLUE);
826                surface.CenterTextf(lastPlayedPos[c].x + 10, lastPlayedPos[c].y + 70, "W");
827             }
828             if(c == lastStart)
829             {
830                surface.SetForeground(LT_RED);
831                surface.CenterTextf(lastPlayedPos[c].x + 10, lastPlayedPos[c].y + 50, "S");
832             }
833          }
834       }
835
836       for(c = 0; c<4; c++)
837       {
838          surface.SetForeground((playedPlayer == c) ? LT_RED : black);
839          surface.CenterTextf(namePos[c].x, namePos[c].y,game.players[c].name);
840       }
841    }
842
843    bool OnLeftButtonDown(int x, int y, Modifiers mods)
844    {
845       if(selectedCard != None && playedPlayer != none)
846       {
847          Player * player = &game.players[playedPlayer];
848          int c;
849
850          for(c=8; c>=0; c--)
851          {
852             int start = c * GAP + player->cards[c].kind * CARD_WIDTH;
853             if(y>=0 && y<CARD_HEIGHT+GAP && x>=start && x<start+CARD_WIDTH)
854             {
855                            if(RUFF_Legal(game, player,c))
856                                    selectedCard=c;
857                break;
858             }
859          }
860          Update(null);
861       }
862       else if(waitingAck)
863       {
864          Player * player = &game.players[game.turn];
865          // Player_Ack4Cards(player);
866       }
867       return true;
868    }
869
870    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
871    {
872       if(selectedCard != None && playedPlayer != none)
873       {
874          Player * player = &game.players[playedPlayer];
875          int c;
876
877          for(c=8; c>=0; c--)
878          {
879             int start = c * GAP + player->cards[c].kind * CARD_WIDTH;
880             if(y>=0 && y<CARD_HEIGHT+GAP && x>=start && x<start+CARD_WIDTH)
881             {
882                            if(RUFF_Legal(game, player,c))
883                {
884                                    selectedCard = c;
885                   Player_PlayCard(player, c);
886                }
887                break;
888             }
889          }
890          Update(null);
891       }
892       return false;
893    }
894
895    bool OnKeyHit(Key key, unichar ch)
896    {
897       if(selectedCard != None && playedPlayer != none)
898       {
899          Player * player = &game.players[playedPlayer];
900          switch((SmartKey)key)
901          {
902             case enter:
903                Player_PlayCard(player, selectedCard);
904                Update(null);
905                break;
906                    case right:
907             {
908                int c;
909                            for(c=0; c<9; c++)
910                            {
911                                    selectedCard++;
912                                    if(selectedCard==9) selectedCard=0;
913                                    if(RUFF_Legal(game, player, selectedCard))
914                                    {
915                                            Update(null);
916                                            break;
917                                    }
918                            }
919                            break;
920             }
921                    case left:
922             {
923                int c;
924                            for(c=0; c<9; c++)
925                            {
926                                    selectedCard--;
927                                    if(selectedCard==-1) selectedCard=8;
928                                    if(RUFF_Legal(game, player,selectedCard))
929                                    {
930                                            Update(null);
931                                            break;
932                                    }
933                            }
934                            break;
935             }
936          }
937       }
938       else if(waitingAck && (SmartKey)key == enter)
939       {
940          Player * player = &game.players[game.turn];
941          // Player_Ack4Cards(player);
942       }
943       return true;
944    }
945
946    bool OnPostCreate()
947    {
948       playedPlayer = none;
949       setup.Create();
950       return true;
951    }
952
953    bool OnLoadGraphics()
954    {
955       int i;
956       cardBack.LoadT(":back.png", null, displaySystem);
957       for(i=0; i<52; i++)
958       {
959          bitmapCards[i] = Bitmap {};
960          bitmapCards[i].LoadT(cardsNames[i], null, displaySystem);
961       }
962       return true;
963    }
964
965    void OnUnloadGraphics()
966    {
967       int i;
968       for(i=0;i<52;i++)
969          delete bitmapCards[i];
970       cardBack.Free();
971    }
972
973    void RUFF_DrawCard(Surface surface, int x, int y, Card card)
974    {
975       Bitmap bitmap;
976       static const int cardNo[9]=
977       {
978          // 5, 7, 8, 9,10,  J,  Q,  K, A
979          4, 6, 7, 8, 9, 10, 11, 12, 0
980       };
981
982       if(card != null)
983          bitmap = bitmapCards[cardNo[card.number] * 4 + card.kind];
984       else
985          bitmap = cardBack;
986
987       surface.Blit(bitmap, x, y, 0,0, bitmap.width,bitmap.height);
988    }
989 }
990
991 RuffApp app;
992
993 class RuffApp : GuiApplication
994 {
995    Ruff ruff {};
996    //fullScreen = true;
997    bool Init()
998    {
999       app = this;
1000       ruff.Create();
1001       ruff.setup.Activate();
1002       return true;
1003    }
1004 }