samples:games: added bomb, poker, tetris, tongIts
authorRejean Loyer <rejean.loyer@gmail.com>
Tue, 17 May 2011 00:44:43 +0000 (20:44 -0400)
committerRejean Loyer <rejean.loyer@gmail.com>
Tue, 17 May 2011 00:44:43 +0000 (20:44 -0400)
12 files changed:
samples/games/bomb/bomb.ec [new file with mode: 0644]
samples/games/bomb/bomb.epj [new file with mode: 0644]
samples/games/poker/bet.ec [new file with mode: 0644]
samples/games/poker/player.ec [new file with mode: 0644]
samples/games/poker/poker.ec [new file with mode: 0644]
samples/games/poker/poker.epj [new file with mode: 0644]
samples/games/poker/pokerutils.ec [new file with mode: 0644]
samples/games/poker/widow.ec [new file with mode: 0644]
samples/games/tetris/tetris.ec [new file with mode: 0644]
samples/games/tetris/tetris.epj [new file with mode: 0644]
samples/games/tongIts/tongIts.epj [new file with mode: 0644]
samples/games/tongIts/tongits.ec [new file with mode: 0644]

diff --git a/samples/games/bomb/bomb.ec b/samples/games/bomb/bomb.ec
new file mode 100644 (file)
index 0000000..ff3181d
--- /dev/null
@@ -0,0 +1,392 @@
+import "ecere"
+
+#define NUMLEVELS 11
+#define DIMX      16
+#define DIMY      16
+#define MAXTIME   (5*60)
+#define TIME2     (4*60)
+#define TIME1     (2*60)
+#define TIMEBAR   gray
+#define TIMEFILL  darkBlue
+
+#define NOTHING   0
+#define PLAYER    1
+#define BOMB5     2
+#define BOMB3     3
+#define BOMB1     4
+#define BOMBD     5
+#define DESACTIV  6
+#define BLOCK     7
+
+#define STATE_MENU      0
+#define STATE_GAME      1
+#define STATE_CREDITS   2
+#define STATE_ENDSCREEN 3
+#define STATE_PASSWORD  4
+
+static char passwords[NUMLEVELS+1][5] =
+{
+   "","1111","2222","3333","4444","5555","6666",
+   "7777","8888","9999","AAAA","BBBB"
+};
+
+BombApp app;
+
+class Bomb : Window
+{
+   borderStyle = sizable, hasMaximize = true, hasMinimize = true, hasClose = true;
+   text = "Bomb Squad", clientSize = Size { 640,400 };
+      
+   bool fullScreen;
+   char board[DIMY][DIMX];
+
+   Bitmap gfx[8];
+   Bitmap mainBitmap {};
+   Bitmap credits {};
+   Bitmap endScreen {};
+   Bitmap password {};
+
+   Size mapSize;
+   Point player;
+   double startTime, secPassed;
+   int level;
+   int state;
+
+   bool DelayExpired()
+   {
+      int x,y, b;
+      double currentTime = GetTime();
+      secPassed = currentTime - startTime;
+           if(secPassed >= TIME2)b=BOMB1;
+      else if(secPassed >= TIME1)b=BOMB3;
+      else                       b=BOMB5;
+
+      for(y=0; y<DIMY; y++)
+         for(x=0; x<DIMX; x++)
+            if((board[y][x]==BOMB1)||(board[y][x]==BOMB3)||(board[y][x]==BOMB5))
+               board[y][x]=(byte)b;
+
+      if(secPassed >= MAXTIME)
+      {
+         state = STATE_MENU;
+         SetPalette(true);
+         timer.Stop();
+      }
+      Update(null);
+      return true;
+   }
+   Timer timer
+   {
+      this, Seconds { 1 }, DelayExpired = DelayExpired
+   };
+   EditBox passEdit
+   {
+      this, textHorzScroll = true, text = "Password", 
+      anchor = Anchor { left = 0.03, top = 0.05, right = 0.84, bottom = 0.80 }, 
+      autoCreate = false
+   };
+   Bitmap buffer {};
+
+   bool IsDone()
+   {
+      bool lost = false;
+      int x,y;
+      for(y=0; y<DIMY; y++)
+         for(x=0; x<DIMX; x++)
+            if((board[y][x]==BOMB1)||(board[y][x]==BOMB3)||(board[y][x]==BOMB5))
+               lost = true;
+      return !lost;
+   }
+
+   void SetPalette(bool flag)
+   {
+      ColorAlpha * palette = null;
+      switch(state)
+      {
+         case STATE_GAME: palette = LoadPalette(":nothing.pcx", null); break;
+         case STATE_MENU: palette = LoadPalette(":max3.pcx", null); break;
+         case STATE_CREDITS: palette = LoadPalette(":3.pcx", null); break;
+         case STATE_ENDSCREEN: palette = LoadPalette(":max3.pcx", null); break;
+      }
+      CopyBytesBy4(buffer.palette, palette, 256);
+      display.SetPalette(palette, flag);
+      delete palette;
+   }
+
+   void LoadLevel(int level)
+   {
+      File f;
+      char map[80];
+
+      // Start the game
+      this.level = level;
+      state = STATE_GAME;
+      timer.Start();
+      startTime = GetTime();
+      sprintf(map,":map%d.dat",level);
+
+      f = FileOpen(map, read);
+      if(f)
+      {
+         int x,y;
+         for(y=0; y<DIMY; y++)
+            for(x=0; x<DIMX; x++)
+            {
+               char ch;
+               f.Getc(&ch);
+               board[y][x] = ch;
+
+               if(board[y][x]==PLAYER)
+               {
+                  player = Point{x,y};
+                  board[y][x]=NOTHING;
+               }
+            }
+         delete f;
+      }
+
+      DelayExpired();
+      SetPalette(true);
+   }
+
+   bool OnStateChange(WindowState state, Modifiers mods)
+   {
+      if(state == maximized && (Key)mods == hotKey)
+      {
+         app.fullScreen = true;
+         app.resolution = res320x200;
+         app.pixelFormat = pixelFormat8;
+         borderStyle = none;
+         anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
+         return false;
+      }
+      return true;
+   }
+
+   bool OnLoadGraphics()
+   {
+      int c;
+      endScreen.Load(":max3.pcx", null, null);
+      mainBitmap.Load(":max3.pcx", null, null);
+      credits.Load(":3.pcx", null, null);
+      password.Load(":password.pcx", null, null);
+
+      for(c = 0; c<8; c++)
+         gfx[c] = Bitmap {};
+      gfx[NOTHING].Load(":nothing.pcx", null, null);
+      gfx[PLAYER].Load(":player.pcx", null, null);
+      gfx[BOMB5].Load(":bomb.pcx", null, null);
+      gfx[BOMB3].Load(":deadeac.pcx", null, null);
+      gfx[BOMB1].Load(":deadeac.pcx", null, null);
+      gfx[BOMBD].Load(":deacbomb.pcx", null, null);
+      gfx[DESACTIV].Load(":desactiv.pcx", null, null);
+      gfx[BLOCK].Load(":block.pcx", null, null);
+
+      mapSize.w = gfx[0].width;
+      mapSize.h = gfx[0].height;
+
+      buffer.AllocateDD(displaySystem, 320, 200);
+
+      SetPalette(true);
+      return true;
+   }
+
+   void OnUnloadGraphics()
+   {
+      int c;
+
+      for(c=0; c<8; c++)
+         delete gfx[c];
+      mainBitmap.Free();
+      credits.Free();
+      endScreen.Free();
+      password.Free();
+      buffer.Free();
+   }
+
+   void OnRedraw(Surface surface2)
+   {
+      Surface surface = buffer.GetSurface(0,0, null);
+
+      surface.SetBackground(black);
+      surface.Clear(colorBuffer);
+      switch(state)
+      {
+         case STATE_GAME:
+         {
+            int x,y;
+            int width;
+            int offX = (320 - mapSize.w * DIMX) / 2;
+            int offY = (200 - mapSize.h * DIMY - 20) / 2;
+
+            for(y=0; y<DIMY; y++)
+               for(x=0; x<DIMX; x++)
+                  surface.Blit(gfx[board[y][x]],
+                     offX + x*mapSize.w, offY + y*mapSize.h, 0,0,
+                     mapSize.w,mapSize.h);
+            surface.Blit(gfx[PLAYER],
+               offX + player.x*mapSize.w, offY + player.y*mapSize.h,
+               0,0,mapSize.w,mapSize.h);
+            
+            surface.SetForeground(TIMEBAR);
+            surface.Rectangle(0,buffer.height - 20,buffer.width-1,buffer.height-1);
+            width = (int)((buffer.width - 2)*(MAXTIME-secPassed)/MAXTIME);
+            surface.SetBackground(TIMEFILL);
+            surface.Area(1,buffer.height - 19,width,buffer.height - 2);
+            break;
+         }
+         case STATE_MENU:
+            surface.Blit(mainBitmap, 0,0, 0,0, mainBitmap.width,mainBitmap.height);
+            break;
+         case STATE_CREDITS:
+            surface.Blit(credits, 0,0, 0,0, credits.width,credits.height);
+            break;
+         case STATE_ENDSCREEN:
+            surface.Blit(endScreen, 0,0, 0,0, endScreen.width,endScreen.height);
+            break;
+         case STATE_PASSWORD:
+            surface.Blit(password, 0,0,0,0,password.width, password.height);
+            break;
+      }
+
+      delete surface;
+      surface2.Stretch(buffer, 0,0, 0,0, clientSize.w, clientSize.h, 
+         buffer.width, buffer.height);
+   }
+
+   bool OnKeyDown(Key key, unichar character)
+   {
+      if(state == STATE_PASSWORD)
+      {
+         if(key == enter)
+         {
+            int l;
+            char * pwd = passEdit.contents;
+            for(l=1; l<=NUMLEVELS; l++)
+               if(!strcmpi(pwd,passwords[l]))
+               {
+                  char string[80];
+                  sprintf(string, "Wrapping to level %d...",l);
+                  MessageBox { text = "Password Accepted", contents = string }.Modal();
+                  LoadLevel(l);
+                  break;
+               }
+         }
+         else if(key != escape)
+            return true;
+
+         passEdit.Destroy(0);
+         if(state == STATE_PASSWORD) state = STATE_MENU;
+         Update(null);
+      }
+      else if(state == STATE_MENU)
+      {
+         switch(key)
+         {
+            case s: LoadLevel(1); break;
+            case p:    
+               state = STATE_PASSWORD;
+               passEdit.Create();
+               break;
+            case x: Destroy(0); return false;
+            case c: state = STATE_CREDITS; SetPalette(true); break;
+         }
+         Update(null);
+      }
+      switch(key)
+      {
+         case escape: 
+            if(state == STATE_GAME)
+               timer.Stop();
+            state = STATE_MENU; 
+            SetPalette(true);
+            Update(null);
+            break;
+         case altEnter:
+            fullScreen = false;
+            borderStyle = sizable, hasClose = true, hasMinimize = true, hasMaximize = true;
+            clientSize = { 640, 400 };
+            return false;
+      }
+      return true;
+   }
+
+   bool OnKeyHit(Key key, unichar ch)
+   {
+      if(state == STATE_GAME)
+      {
+         int dx=0,dy=0;
+
+         switch(key)
+         {
+            case up: dy=-1; break;
+            case down: dy=1; break;
+            case left: dx=-1; break;
+            case right: dx=1; break;
+            default: return true;
+         }
+
+         if((player.x+dx<0)||(player.y+dy<0)||(player.x+dx>=DIMX)||(player.y+dy>=DIMY))
+            return true;
+
+         if(board[player.y+dy][player.x+dx]==BLOCK) return true;
+         if((board[player.y+dy][player.x+dx]==BOMB5)
+          ||(board[player.y+dy][player.x+dx]==BOMB3)
+          ||(board[player.y+dy][player.x+dx]==BOMB1)
+          ||(board[player.y+dy][player.x+dx]==BOMBD))
+         {
+            if((player.x+dx*2<0)||(player.y+dy*2<0)||(player.x+dx*2>=DIMX)||(player.y+dy*2>=DIMY))
+               return true;
+            if((board[player.y+2*dy][player.x+2*dx]!=DESACTIV)&&
+               (board[player.y+2*dy][player.x+2*dx]!=NOTHING))
+               return true;
+            if(board[player.y+dy][player.x+dx]==BOMBD)
+               board[player.y+dy][player.x+dx]=DESACTIV;
+            else
+               board[player.y+dy][player.x+dx]=NOTHING;
+            if(board[player.y+2*dy][player.x+2*dx]==DESACTIV)
+               board[player.y+2*dy][player.x+2*dx]=BOMBD;
+            else
+            {
+               int b;
+                    if(secPassed >= TIME2)b=BOMB1;
+               else if(secPassed >= TIME1)b=BOMB3;
+               else                             b=BOMB5;
+               board[player.y+2*dy][player.x+2*dx]=(byte)b;
+            }
+         }
+
+         player.x+=dx;
+         player.y+=dy;
+
+         if(IsDone())
+         {
+            if(level == NUMLEVELS)
+            {
+               state = STATE_ENDSCREEN;
+               SetPalette(true);
+            }
+            else
+            {
+               char string[80];
+               sprintf(string, "Password to level %d is: %s",level+1,passwords[level+1]);
+               timer.Stop();
+               MessageBox { text = "Congratulations! You win!", contents = string }.Modal();
+               LoadLevel(level + 1);
+            }
+         }
+         Update(null);
+      }
+      return true;
+   }
+}
+
+class BombApp : GuiApplication
+{
+   Bomb bomb {};
+   void Main()
+   {
+      app = this;
+      GuiApplication::Main();
+   }
+}
diff --git a/samples/games/bomb/bomb.epj b/samples/games/bomb/bomb.epj
new file mode 100644 (file)
index 0000000..8372343
--- /dev/null
@@ -0,0 +1,99 @@
+
+ECERE Project File
+
+Version 0.1a
+
+Target "bomb"
+
+   Configurations
+
+    + Debug
+
+         Compiler Options
+
+            Intermediate Directory = Debug
+            Debug = True
+            Optimize = None
+            Profile = False
+            MemoryGuard = False
+            AllWarnings = True
+            Strict Name Spaces = False
+
+         Linker Options
+
+            Target Name = bomb
+            Target Type = Executable
+            Target Directory = Debug
+            Console = False
+
+            Libraries = ecere
+
+    + MemoryGuard
+
+         Compiler Options
+
+            Intermediate Directory = MemoryGuard
+            Debug = True
+            Optimize = None
+            Profile = False
+            MemoryGuard = True
+            AllWarnings = True
+            Strict Name Spaces = False
+
+         Linker Options
+
+            Target Name = bomb
+            Target Type = Executable
+            Target Directory = MemoryGuard
+            Console = True
+
+            Libraries = ecere
+
+    + Release
+
+         Compiler Options
+
+            Intermediate Directory = Release
+            Debug = False
+            Optimize = Speed
+            Profile = False
+            MemoryGuard = False
+            AllWarnings = True
+            Strict Name Spaces = False
+
+         Linker Options
+
+            Target Name = bomb
+            Target Type = Executable
+            Target Directory = Release
+            Console = False
+
+            Libraries = ecere
+
+   Files
+
+    - bomb.ec
+
+   Resources
+
+    = data/map1.dat
+    = data/map10.dat
+    = data/map11.dat
+    = data/map2.dat
+    = data/map3.dat
+    = data/map4.dat
+    = data/map5.dat
+    = data/map6.dat
+    = data/map7.dat
+    = data/map8.dat
+    = data/map9.dat
+    = data/3.pcx
+    = data/block.pcx
+    = data/bomb.pcx
+    = data/deacbomb.pcx
+    = data/deadeac.pcx
+    = data/desactiv.pcx
+    = data/max3.pcx
+    = data/nothing.pcx
+    = data/password.pcx
+    = data/player.pcx
diff --git a/samples/games/poker/bet.ec b/samples/games/poker/bet.ec
new file mode 100644 (file)
index 0000000..9891558
--- /dev/null
@@ -0,0 +1,67 @@
+/****************************************************************************
+   POKER Game Interface
+
+   Copyright (c) 2001 Jerome Jacovella-St-Louis
+   All Rights Reserved.
+   
+   bet.ec - Poker Bet Window
+****************************************************************************/
+import "poker.ec"
+
+class Bet : Window
+{
+   background = activeBorder;
+   borderStyle = fixed;
+   clientSize = Size { 140, 80 };
+
+   int * thisBet;
+   Button bet
+   {
+      this,
+      text = "Bet",
+      size = Size { 40, 20 },
+      anchor = Anchor { horz = -20 };
+      hotKey = b,
+      isDefault = true;
+
+      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+      {
+         int theBet = (int) strtod(edit.contents, null) * 2;
+         if(theBet > 0 && *thisBet + theBet >= currentBet)
+         {
+            *thisBet += theBet;
+            Destroy(1);
+         }
+         return true;
+      }
+   };
+   Button pass
+   {
+      this,
+      text = currentBet ? "Fold" : "Pass",
+      size = Size { 40, 20 },
+      anchor = Anchor { horz = 20 },
+      hotKey = currentBet ? f : p;
+
+      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+      {
+         Destroy(0);
+         return true;
+      }
+   };
+
+   bool OnKeyHit(Key key, unichar ch)
+   {
+      if(key == escape) Destroy(0);
+      return true;
+   }
+   EditBox edit { this, anchor = Anchor { top = 10 }, size = Size { 80, 20 } };
+
+   property int * thisBet { set { this.thisBet = value; } };
+
+   void OnRedraw(Surface surface)
+   {
+      surface.SetForeground(red);
+      surface.WriteTextf(0, 65, "$%.2f to you.", (currentBet - *thisBet) / 2.0);
+   }
+}
diff --git a/samples/games/poker/player.ec b/samples/games/poker/player.ec
new file mode 100644 (file)
index 0000000..d5ba09e
--- /dev/null
@@ -0,0 +1,74 @@
+/****************************************************************************
+   POKER Game Interface
+
+   Copyright (c) 2001 Jerome Jacovella-St-Louis
+   All Rights Reserved.
+   
+   player.ec - Poker Player Window
+****************************************************************************/
+import "poker.ec"
+import "pokerUtils.ec"
+
+static char handTypes[10][20] = 
+{
+   "NOTHING",
+   "ONE PAIR",
+   "TWO PAIRS",
+   "THREE OF A KIND",
+   "STRAIGHT",
+   "FLUSH",
+   "FULL HOUSE",
+   "FOUR OF A KIND",
+   "STRAIGHT FLUSH",
+   "ROYAL FLUSH"
+};
+
+class Player : Window
+{
+   borderStyle = sizable;
+
+   bool human;
+   int numUp, numDown;
+   int money;
+   int up  [52];
+   int down[52];
+   int thisBet;
+   bool folded;
+   int bestHand[5];
+   int handType;
+   bool winner;
+
+   Player()
+   {
+      money = 40 * 2;
+   }
+
+   void OnRedraw(Surface surface)
+   {
+      Poker poker = (Poker)master;
+      int c;
+
+      for(c=0; c<numDown; c++)
+      {
+         poker.DrawCard(surface, c*15, 0, (human || gameOver && !folded) ? POKER_Card(down[c]) : -1);
+      }
+      POKER_HandType(bestHand);
+      for(c=0; c<numUp; c++)
+         poker.DrawCard(surface, c*15, 40, folded ? -1 : POKER_Card(up[c]));
+      if(folded)
+      {
+         surface.SetForeground(blue);
+         surface.WriteTextf(10, 130, "FOLDED");
+      }
+      else if(gameOver)
+      {
+         surface.SetForeground(red);
+         if(winner) 
+            surface.WriteTextf(10, 130, "WINNER");
+         surface.SetForeground(blue);
+         surface.WriteTextf(80, 130, "%s", handTypes[handType]);
+      }
+      surface.SetForeground(white);
+      surface.WriteTextf(110, 110, "$%.2f", money / 2.0);
+   }
+}
diff --git a/samples/games/poker/poker.ec b/samples/games/poker/poker.ec
new file mode 100644 (file)
index 0000000..413e4f5
--- /dev/null
@@ -0,0 +1,462 @@
+/****************************************************************************
+   POKER Game Interface
+
+   Copyright (c) 2001 Jerome Jacovella-St-Louis
+   All Rights Reserved.
+   
+   poker.ec - Poker Main Window
+****************************************************************************/
+import "ecere"
+import "player.ec"
+import "widow.ec"
+import "bet.ec"
+
+enum PokerHand { nothing, onePair, twoPair, threeOfAKind, straight, flush, fullHouse, fourOfAKind, straightFlush, royalFlush };
+
+/*
+ROYAL FLUSH        0.0002 % 
+STRAIGHT FLUSH     0.0012 % 
+FOUR OF A KIND     0.0240 % 
+FULL HOUSE         0.1441 % 
+FLUSH              0.1967 % 
+STRAIGHT           0.3532 % 
+THREE OF A KIND    2.1128 % 
+TWO PAIR           4.7539 % 
+ONE PAIR          42.2569 % 
+NOTHING           50.1570 % 
+*/
+
+enum Facing { faceDown, faceUp };
+
+static int lowHand[5] = { 4*0 + 1, 4*1, 4*2, 4*3, 4*5 };
+static Player players[6];
+static int deck[52], deckIndex;
+
+static int numPlayers;
+static int numPlayersLeft;
+static char playerNames[6][20] =
+{
+   "Jerome",
+   "Adam",
+   "Jason",
+   "Bruce",
+   "Pete",
+   "Daniel"
+};
+static Pointf positions[5][6] =
+{
+   {{ .50f, .82f }, { .50f, .18f }},
+   {{ .50f, .82f }, { .18f, .18f },  { .82f, .18f}},
+   {{ .50f, .82f }, { .18f, .50f },  { .50f, .18f},  { .82f, .50f}},
+   {{ .50f, .82f }, { .18f, .50f },  { .50f, .18f},  { .82f, .50f}, { .82f, .50f}},
+   {{ .25f, .82f }, { .18f, .50f },  { .25f, .18f},  { .75f, .18f}, { .82f, .50f}, { .75f, .82f}}
+};
+
+// --- Data Used by Child Window Classes ---
+int currentBet;
+int potMoney;
+int widowNum = 0;
+int widow[52];
+bool gameOver = true;
+
+define ANTE = 1;
+
+class Poker : Window
+{
+   background = teal;
+   hasMinimize = true, hasMaximize = true, hasClose = true;
+   borderStyle = sizable;
+   text = "ECERE Poker";
+   size = Size { 800, 600 };
+
+   Bitmap bitmapCards[52];
+   Bitmap cardBack {};
+
+   Widow widowWindow { this, opacity = 0, text = "Widow", borderStyle = sizable, anchor = Anchor { left = 0.375, top = 0.34, right = 0.375, bottom = 0.34 } };
+
+   void DrawCard(Surface surface, int x, int y, int card)
+   {
+      Bitmap bitmap;
+      if(card != -1)
+         bitmap = bitmapCards[card];
+      else
+         bitmap = cardBack;
+      surface.Blit(bitmap, x, y, 0,0, bitmap.width,bitmap.height);
+   }
+
+   // --- Poker Game Flow ---
+
+   void CreatePlayers(int num)
+   {
+      int c;
+
+      numPlayers = num;
+      for (c = 0; c<numPlayers; c++)
+      {
+         char string[256];
+         Pointf pos = positions[numPlayers - 2][c];
+
+         sprintf(string, "%s (%d)", playerNames[c], c + 1);
+         players[c] = Player { this, opacity = 0, text = string, anchor = Anchor { left = pos.x - 0.175, top = pos.y - 0.16, right = 1-(pos.x + 0.175), bottom = 1-(pos.y + 0.16) } };
+         players[c].Create();
+      }
+      players[0].human = true;
+   }
+
+   void Shuffle()
+   {
+      int c;
+
+      POKER_ShuffleDeck(deck);
+      deckIndex = 0;
+      numPlayersLeft = numPlayers;
+      for(c = 0; c<numPlayers; c++)
+      {
+         players[c].numDown = players[c].numUp = 0;
+         players[c].folded = false;
+         players[c].winner = false;
+      }
+      widowNum = 0;
+      gameOver = false;
+   }
+
+   void Deal(Facing up, int howMany)
+   {
+      int c;
+      int p;
+
+      for(c = 0; c<howMany; c++)
+         for(p = 0; p<numPlayers; p++)
+         {
+            Player player = players[p];
+            if(!player.folded)
+            {
+               if(up)
+               {
+                  player.up[player.numUp++] = deck[deckIndex++];
+                  POKER_SortCards(player.up, player.numUp);
+               }
+               else
+               {
+                  player.down[player.numDown++] = deck[deckIndex++];
+                  POKER_SortCards(player.down, player.numDown);
+               }
+            }
+         }
+      Update(null);
+   }
+
+   void DealWidow(int howMany)
+   {
+      int c;
+      for(c = 0; c<howMany; c++)
+         widow[widowNum++] = deck[deckIndex++];
+      POKER_SortCards(widow, widowNum);
+      Update(null);
+   }
+
+   void Ante()
+   {
+      int c;
+      for(c = 0; c<numPlayers; c++)
+      {
+         if(players[c].money >= ANTE)
+         {
+            players[c].money -= ANTE;
+            potMoney += ANTE;
+         }
+         else
+            players[c].folded = true;
+      }
+      Update(null);
+   }
+
+   void BettingRound(int firstBet)
+   {
+      int p;
+      int numBets = 0;
+
+      if(!created) return;
+
+      if(numPlayersLeft >= 2) 
+      {
+         currentBet = 0;
+         for(p = 0; p<numPlayers; p++)
+            players[p].thisBet = 0;
+
+         for(p = firstBet;; p++)
+         {
+            Player player;
+            char string[64];
+            Bet bet;
+
+            if(p == numPlayers) p = 0;
+            player = players[p];
+            if(player.folded) continue;
+
+            if(currentBet && player.thisBet == currentBet) break;
+
+            sprintf(string, "Your bet, %s?", playerNames[p]);
+            bet = Bet { parent = this, thisBet = &player.thisBet, text = string };
+            bet.Create();
+            eInstance_IncRef(bet);
+            while(bet.created)
+            {
+               app.UpdateDisplay();
+               if(!app.ProcessInput(true))
+                  app.Wait();
+            }
+            eInstance_DecRef(bet);
+
+            if(!created) return;
+            
+            //player.thisBet = 0;
+         
+            if(player.thisBet < currentBet)
+            {
+               player.folded = true;
+               numPlayersLeft--;
+               if(numPlayersLeft < 2)
+                  break;
+               numBets = 0;
+            }
+            else if(player.thisBet > currentBet)
+            {
+               currentBet = player.thisBet;
+               numBets = 0;
+            }
+            else
+               numBets++;
+            potMoney += player.thisBet;
+            player.money -= player.thisBet;
+            Update(null);
+
+            if(!currentBet && numBets >= numPlayersLeft)
+               break;
+         }
+      }
+   }
+
+   void WinMoney(int numHand, int numWidow)
+   {
+      int p;
+      int numWinners = 0;
+      int bestHand[5] = { lowHand[0], lowHand[1], lowHand[2], lowHand[3], lowHand[4] };
+
+      if(!created) return;
+
+      for(p=0; p<numPlayers; p++)
+      {
+         int cards[16];
+         int c;
+         Player player = players[p];
+
+         if(player.folded) continue;
+
+         for(c = 0;; c++)
+         {
+            if(c < player.numDown)
+               cards[c] = player.down[c];
+            else if(c - player.numDown < player.numUp)
+               cards[c] = player.up[c - player.numDown];
+            else
+               break;
+         }
+         CopyBytesBy4(player.bestHand, lowHand, 5);
+         POKER_BestHand(cards, widow, c, widowNum, numHand, numWidow, player.bestHand);
+         player.handType = POKER_HandType(player.bestHand);
+      }
+
+      for(p=0; p<numPlayers; p++)
+      {
+         int c;
+         Player player = players[p];
+         if(player.folded) continue;
+
+         switch(POKER_Compare(bestHand, player.bestHand))
+         {
+            case 0:
+               numWinners ++;
+               player.winner = true;
+               break;
+            case 1:
+               for(c=0; c<numPlayers; c++)
+                  players[c].winner = false;
+               numWinners = 1;
+               CopyBytesBy4(bestHand, player.bestHand, 5);
+               player.winner = true;
+               break;
+         }
+      }
+      for(p=0; p<numPlayers; p++)
+      {
+         Player player = players[p];
+         if(player.folded) continue;
+         if(POKER_Compare(player.bestHand, bestHand) == 0)
+            player.money += potMoney / numWinners;
+      }
+      if(numWinners)
+      {
+         potMoney -= (potMoney / numWinners) * numWinners;
+      }
+      gameOver = true;
+      Update(null);
+   }
+
+   // --- Poker Games Definitions ---
+
+   /*
+   TEXAS HOLDEM - The most popular poker game in Blackhawk. A variation of 7-Card 
+   Stud where every player gets dealt 2 cards face down and there is a community
+   board of 5 cards. Players Ise the 2 cards in their hand plus the 5 community
+   cards to make the best possible 5 card hand. A dealers button moves around the
+   table each hand. The player to the left of the dealer button is dealt the 
+   first card. Also the person to the left of the button has to post a blind. 
+   There is a betting round after the players receive their first 2 cards. Then the 
+   dealer places 3 cards on the board (the flop) and there is a betting round. Then 
+   the dealer places another card on the board (the turn) and there is another 
+   betting round. Then the dealer places the final card (the river) on the board 
+   and there is a final betting round. Games may have 1 blind or 2 blinds. Games 
+   vary from $2-5 betting to straight $5 betting.
+   */
+   void TexasHoldem()
+   {
+      Shuffle();
+      Ante();
+      Deal(faceDown, 2);
+      BettingRound(0);
+      DealWidow(3);
+      BettingRound(0);
+      DealWidow(1);
+      BettingRound(0);
+      DealWidow(1);
+      BettingRound(0);
+      WinMoney(2, 5);
+   }
+
+   /*
+   OMAHA - A games similar to Texas Holdem except the players are dealt 4 cards 
+   face down. There is a board of 5 community cards and you must Ise 2 cards out
+   of your hand to make the best possible hand. The game may be played straight 
+   high or high/lowHand. There is a dealer button that moves around the table each 
+   hand and the player that has the dealers button may choose to play the game 
+   straight high or high/lowHand. The player to the left of the dealer button has 
+   to post a small blind of $1 and the person to his/her left has to post the 
+   large blind of $2. To qualify for a lowHand hand, the player must have 5 cards 
+   that are 8 or lowHander. There is a betting round after the players receive their 
+   4 cards. Then the dealer places 3 cards on the board (the flop). After the 
+   betting round, the dealer places another card on the board (the turn) and there 
+   is another betting round. Then the dealer places the last card (the river) on 
+   the board and there is a final betting round. The betting limits are Isually 
+   $2-$5.
+   */
+   void OmahaHoldem()
+   {
+      Shuffle();
+      Ante();
+      Deal(faceDown, 4);
+      BettingRound(0);
+      DealWidow(3);
+      BettingRound(0);
+      DealWidow(1);
+      BettingRound(0);
+      DealWidow(1);
+      BettingRound(0);
+      WinMoney(2, 3);
+   }
+
+   void SevenCardStud()
+   {
+      Shuffle();
+      Ante();
+      Deal(faceDown, 2);
+      Deal(faceUp, 1);
+      BettingRound(0);
+      Deal(faceUp, 1);
+      BettingRound(0);
+      Deal(faceUp, 1);
+      BettingRound(0);
+      Deal(faceUp, 1);
+      BettingRound(0);
+      Deal(faceDown, 1);
+      BettingRound(0);
+      WinMoney(5, 0);
+   }
+
+   // --- Poker Window Class ---
+   bool OnLoadGraphics()
+   {
+      Bitmap ptrCardLoad {};
+      if(ptrCardLoad.Load(":cards.pcx",null,null))
+      {
+         int i;
+         cardBack.LoadT(":ecereCard.bmp",null,displaySystem);
+      
+         for(i = 0; i < 52; i++)
+         {
+            bitmapCards[i] = Bitmap {};
+            bitmapCards[i].Allocate(null,ptrCardLoad.width, ptrCardLoad.height/52,0,pixelFormat8,true);
+            CopyBytesBy4(bitmapCards[i].palette, ptrCardLoad.palette, 256);
+            bitmapCards[i].Grab(ptrCardLoad,0,(ptrCardLoad.height/52)*i);
+            bitmapCards[i].transparent = true;
+            bitmapCards[i].MakeDD(displaySystem);
+         }
+      }
+      delete ptrCardLoad;
+      return true;
+   }
+
+   void OnUnloadGraphics()
+   {
+      int i;
+      for(i=0;i<52;i++)
+         bitmapCards[i].Free();
+      cardBack.Free();
+   }
+
+   bool OnPostCreate()
+   {
+      potMoney = 0;
+      CreatePlayers(6);
+      return true;
+   }
+
+   bool OnClose(bool parentClosing)
+   {
+      if(MessageBox { type = yesNo, text = "Exit", contents = "Quit?" }.Modal() == yes)
+         return true;
+      return false;
+   }
+
+   bool OnKeyHit(Key key, unichar ch)
+   {
+      if(!gameOver) return false;
+      switch(key)
+      {
+         case f1: TexasHoldem(); break;
+         case f2: OmahaHoldem(); break;
+         case f3: SevenCardStud();   break;
+      }
+      return true;
+   }
+}
+
+PokerApp app;
+
+class PokerApp : GuiApplication
+{
+   Poker { };
+   appName = "Poker Master";
+
+   bool Init()
+   {
+      int c;
+      // Initialize Card Deck
+      RandomSeed((int)(GetTime() * 1000));
+      for(c = 0; c<52; c++)
+         deck[c] = c;
+
+      app = this;
+      return true;
+   }
+}
diff --git a/samples/games/poker/poker.epj b/samples/games/poker/poker.epj
new file mode 100644 (file)
index 0000000..c7f3259
--- /dev/null
@@ -0,0 +1,35 @@
+
+ECERE Project File
+
+Version 0a
+
+Target "poker"
+
+   Compiler Options
+
+      Intermediate Directory = obj
+      Debug = True
+      Optimize = False
+      Profile = False
+      AllWarnings = True
+
+   Linker Options
+
+      Target Name = poker
+      Target Type = Executable
+      Console = False
+
+      Libraries = ecere
+
+   Files
+
+    - bet.ec
+    - player.ec
+    - poker.ec
+    - pokerutils.ec
+    - widow.ec
+
+   Resources
+
+    = data/ecereCard.bmp
+    = data/cards.pcx
diff --git a/samples/games/poker/pokerutils.ec b/samples/games/poker/pokerutils.ec
new file mode 100644 (file)
index 0000000..389b490
--- /dev/null
@@ -0,0 +1,429 @@
+/****************************************************************************
+   POKER Game Interface
+
+   Copyright (c) 2001 Jerome Jacovella-St-Louis
+   All Rights Reserved.
+   
+   pokerutils.c - Poker Backend Utilities
+****************************************************************************/
+import "poker.ec"
+
+// --- Data ---
+
+static int handsRests[10] = { 5, 3, 1, 2, 0, 0, 0, 1, 0, 0 };
+
+// { 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A }
+// { 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A }
+// { 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A }
+// { 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A }
+
+// --- Static Utilities ---
+
+static int Compare(const int * a, const int * b)
+{
+   if(*a > *b) return 1; else if(*a < *b) return -1; else return 0;
+}
+
+static bool POKER_Straight(int cards[5])
+{
+   int c;
+   for(c = 1; c<5; c++)
+      if((cards[c] / 4 != cards[c-1] / 4 + 1) && !(cards[c - 1] / 4 == 12 && cards[c] / 4 == 0))
+         return false;
+   return true;
+}
+
+static bool POKER_Flush(int cards[5])
+{
+   int c;
+   for(c = 1; c<5; c++)
+      if(cards[c] % 4 != cards[0] % 4)
+         return false;
+   return true;
+}
+
+static bool POKER_Same(int cards[5], int howMany, int what[2], int rest[3])
+{
+   int c;
+   int card;
+   int numPairs = 0;
+
+   for(card = 0; card<13; card++)
+   {
+      int num = 0;
+      for(c = 0; c < 5; c++)
+      {
+         if(cards[c] / 4 == card)
+            num++;
+      }
+      if(num == howMany)
+      {
+         what[numPairs++] = card;
+      }
+   }
+   if(numPairs) 
+   {
+      int d;
+      qsort(what, numPairs, sizeof(int), Compare);
+      for(d = 0, c = 0; c<5; c++)
+      {
+         int w;
+         for(w = 0; w < numPairs; w++)
+            if(cards[c] / 4 == what[w])
+               break;
+         if(w == numPairs)
+            rest[d++] = cards[c];
+      }
+   }
+   return numPairs;
+}
+
+// --- External Functions ---
+
+void POKER_SortCards(int * cards, int numCards)
+{               
+   qsort(cards, numCards, sizeof(int), Compare);
+}
+
+int POKER_Card(int card)
+{
+   if(card / 4 == 12)
+      card -= 13 * 4;
+   card += 4;
+   return card;
+}
+
+void POKER_ShuffleDeck(int deck[52])
+{
+   int t;
+   int count;
+
+   count = GetRandom(1000, 2000);
+   for(t = 0; t<count; t++)
+   {
+      // cut the deck in 2
+      int cuts[2][52];
+      int numCut[2];
+      int indexCut[2] = {0,0};
+      int cut = GetRandom(13, 39);
+      int c;
+
+      for(c = 0; c<cut; c++)
+         cuts[0][c] = deck[c];
+      for(c = cut; c<52; c++)
+         cuts[1][c - cut] = deck[c];
+
+      numCut[0] = cut;
+      numCut[1] = 52 - cut;
+
+      // Mix the cards
+      for(c = 0; c<52; c++)
+      {
+         int whichCut;
+         
+         if(indexCut[0] < numCut[0] && indexCut[1] < numCut[1])
+            whichCut = GetRandom(0,1);
+         else if(indexCut[0] < numCut[0])
+            whichCut = 0;
+         else if(indexCut[1] < numCut[1])
+            whichCut = 1;
+
+         deck[c] = cuts[whichCut][indexCut[whichCut]++];
+      }
+   }
+}
+
+PokerHand POKER_HandType(int cards[5])
+{
+   bool flush, straight;
+   int numPairs, numTris, numQuads;
+   int rest[5];
+   int pairs[2], tris, quads;
+
+   /*** DETERMINE HAND TYPE ***/
+   flush    = POKER_Flush(cards);
+   straight = POKER_Straight(cards);
+   numPairs = POKER_Same(cards, 2, pairs, rest);
+   numTris  = POKER_Same(cards, 3, &tris, rest);
+   numQuads = POKER_Same(cards, 4, &quads, rest);
+
+   if(straight && flush)
+   {
+      if(cards[4] / 4 == 12)
+         return royalFlush;
+      else
+         return straightFlush;
+   }
+   else if(numQuads)
+      return fourOfAKind;
+   else if(numPairs && numTris)
+      return fullHouse;
+   else if(flush)
+      return PokerHand::flush;
+   else if(straight)
+      return PokerHand::straight;
+   else if(numTris)
+      return threeOfAKind;
+   else if(numPairs == 2)
+      return twoPair;
+   else if(numPairs)
+      return onePair;
+   else
+      return nothing;
+}
+
+int POKER_Compare(int cards1[5], int cards2[5])
+{
+   bool flush[2], straight[2];
+   int numPairs[2], numTris[2], numQuads[2];
+   int * cards;
+
+   int rest[2][5];
+   int pairs[2][2], tris[2], quads[2];
+   PokerHand handType[2];
+   int h;
+   int c;
+   int numRest[2];
+
+   int winner = 0;
+
+   for(h = 0; h<2; h++)
+   {
+      cards = (h == 0) ? cards1 : cards2;
+
+      /*** DETERMINE HAND TYPE ***/
+      flush[h]    = POKER_Flush(cards);
+      straight[h] = POKER_Straight(cards);
+      numPairs[h] = POKER_Same(cards, 2, pairs[h], rest[h]);
+      numTris[h]  = POKER_Same(cards, 3, &tris[h], rest[h]);
+      numQuads[h] = POKER_Same(cards, 4, &quads[h], rest[h]);
+
+      if(straight[h] && flush[h])
+      {
+         if(cards[4] / 4 == 12)
+            handType[h] = royalFlush;
+         else
+            handType[h] = straightFlush;
+      }
+      else if(numQuads[h])
+         handType[h] = fourOfAKind;
+      else if(numPairs[h] && numTris[h])
+         handType[h] = fullHouse;
+      else if(flush[h])
+         handType[h] = PokerHand::flush;
+      else if(straight[h])
+         handType[h] = PokerHand::straight;
+      else if(numTris[h])
+         handType[h] = threeOfAKind;
+      else if(numPairs[h] == 2)
+         handType[h] = twoPair;
+      else if(numPairs[h])
+         handType[h] = onePair;
+      else
+      {
+         handType[h] = nothing;
+         CopyBytesBy4(rest[h], cards, 5);
+      }
+      numRest[h] = handsRests[handType[h]];
+   }
+
+   /*** DETERMINE WINNING HAND ***/
+   if(handType[1] > handType[0])
+      winner = 1;
+   else if(handType[0] > handType[1])
+      winner = -1;
+   else
+   {
+      switch(handType[0])
+      {
+         case straightFlush:
+            if(cards2[4] / 4 > cards1[4] / 4)
+               winner = 1;
+            else if(cards1[4] / 4> cards2[4] / 4)
+               winner = -1;
+            break;
+         case fourOfAKind:
+            if(quads[1] > quads[0] )
+               winner = 1;
+            else if(quads[0] > quads[1])
+               winner = -1;
+            break;
+         case fullHouse:
+            if(tris[1] > tris[0] )
+               winner = 1;
+            else if(tris[0] > tris[1])
+               winner = -1;
+            else if(pairs[1][0] > pairs[0][0])
+               winner = 1;
+            else if(pairs[0][0] > pairs[1][0])
+               winner = -1;
+            break;
+         case PokerHand::flush:
+            for(c = 4; c>=0; c--)
+            {
+               if(cards2[c] / 4 > cards1[c] / 4)
+               {
+                  winner = 1;
+                  break;
+               }
+               else if(cards1[c] / 4 > cards2[c] / 4)
+               {
+                  winner = -1;
+                  break;
+               }
+            }
+            break;
+         case PokerHand::straight:
+            if(cards2[4] / 4> cards1[4] / 4)
+               winner = 1;
+            else if(cards1[4] / 4> cards2[4] / 4)
+               winner = -1;
+            break;
+         case threeOfAKind:
+            if(tris[1] > tris[0] )
+               winner = 1;
+            else if(tris[0] > tris[1])
+               winner = -1;
+            break;
+         case twoPair:
+            if(pairs[1][1] > pairs[0][1])
+               winner = 1;
+            else if(pairs[0][1] > pairs[1][1])
+               winner = -1;
+            else if(pairs[1][0] > pairs[0][0])
+               winner = 1;
+            else if(pairs[0][0] > pairs[1][0])
+               winner = -1;
+            break;
+         case onePair:
+            if(pairs[1][0] > pairs[0][0])
+               winner = 1;
+            else if(pairs[0][0] > pairs[1][0])
+               winner = -1;
+            break;
+      }
+
+      /*** NO WINNER FROM TYPES, TRY TO SPLIT WITH THE rest ***/
+      if(!winner)
+      {
+         for(c = numRest[0] - 1; c>=0; c--)
+         {
+            if(rest[1][c] / 4> rest[0][c] / 4)
+            {
+               winner = 1;
+               break;
+            }
+            else if(rest[0][c] / 4 > rest[1][c] / 4)
+            {
+               winner = -1;
+               break;
+            }
+         }
+      }
+   }
+   return winner;
+}
+
+void POKER_BestHand(int * cards1, int * cards2, int n1, int n2, int r1, int r2, int output[5])
+{
+   static int pos = 0;
+   static int start1 = 0;
+   static int start2 = 0;
+   static int currentHand[5];
+
+   if(pos == 5)
+   {
+      int temp[5];
+      CopyBytesBy4(temp, currentHand, 5);
+      qsort(temp, 5, sizeof(int), Compare);
+      if(POKER_Compare(output, temp) == 1)
+         CopyBytesBy4(output, temp, 5);
+   }
+   else
+   {
+      int oldStart, c;
+
+      if(pos >= r1)
+      {
+         oldStart = start2;
+         for(c = start2; c < n2 - (5 - pos - 1); c++)
+         {
+            start2 = c + 1;
+            currentHand[pos++] = cards2[c];
+            POKER_BestHand(cards1, cards2, n1, n2, r1, r2, output);
+            pos--;
+         }
+         start2 = oldStart;
+      }
+      else
+      {
+         oldStart = start1;
+         for(c = start1; c < n1 - (r1 - pos - 1); c++)
+         {
+            start1 = c + 1;
+            currentHand[pos++] = cards1[c];
+            POKER_BestHand(cards1, cards2, n1, n2, r1, r2, output);
+            pos--;
+         }
+         start1 = oldStart;
+      }
+
+      // Added this recently : was only using 5-r1 from cards2
+      if(pos >= r2)
+      {
+         oldStart = start1;
+         for(c = start1; c < n1 - (5 - pos - 1); c++)
+         {
+            start1 = c + 1;
+            currentHand[pos++] = cards1[c];
+            POKER_BestHand(cards1, cards2, n1, n2, r1, r2, output);
+            pos--;
+         }
+         start1 = oldStart;
+      }
+      else
+      {
+         oldStart = start2;
+         for(c = start2; c < n2 - (r2 - pos - 1); c++)
+         {
+            start2 = c + 1;
+            currentHand[pos++] = cards2[c];
+            POKER_BestHand(cards1, cards2, n1, n2, r1, r2, output);
+            pos--;
+         }
+         start2 = oldStart;
+      }
+   }
+}
+
+/*
+void POKER_BestHand(int * cards, int n, int output[5])
+{
+   static int pos = 0;
+   static int start = 0;
+   static int currentHand[5];
+   int c;
+
+   for(c = start; c < n - (5 - pos - 1); c++)
+   {
+      currentHand[pos] = cards[c];
+      if(pos == 5 - 1)
+      {
+         int temp[5];
+         CopyBytesBy4(temp, currentHand, 5);
+         qsort(temp, 5, sizeof(int), Compare);
+         if(POKER_Compare(output, temp) == 1)
+            CopyBytesBy4(output, temp, 5);
+      }
+      else
+      {
+         int oldStart = start;
+         start = c + 1;
+         pos++;
+         POKER_BestHand(cards, n, output);
+         pos--;
+         start = oldStart;
+      }
+   }
+}
+*/
diff --git a/samples/games/poker/widow.ec b/samples/games/poker/widow.ec
new file mode 100644 (file)
index 0000000..d6ed6bb
--- /dev/null
@@ -0,0 +1,22 @@
+/****************************************************************************
+   POKER Game Interface
+
+   Copyright (c) 2001 Jerome Jacovella-St-Louis
+   All Rights Reserved.
+   
+   widow.ec - Widow Window
+****************************************************************************/
+import "poker.ec"
+
+class Widow : Window
+{
+   void OnRedraw(Surface surface)
+   {
+      Poker poker = (Poker) master;
+      int c;
+      for(c=0; c<widowNum; c++)
+         poker.DrawCard(surface, c * 15, 0, POKER_Card(widow[c]));
+      surface.SetForeground(red);
+      surface.WriteTextf(10, 130, "POT MONEY: %.2f", potMoney / 2.0);
+   }
+}
diff --git a/samples/games/tetris/tetris.ec b/samples/games/tetris/tetris.ec
new file mode 100644 (file)
index 0000000..fd0cc01
--- /dev/null
@@ -0,0 +1,614 @@
+/****************************************************************************
+   Tetris Game
+
+   Copyright (c) 2001-2007 Jerome Jacovella-St-Louis
+   All Rights Reserved.
+   
+   tetris.ec - Tetris
+****************************************************************************/
+import "ecere"
+
+// --- Definitions ---
+
+define SERVER = 0;
+define CLIENT = 1;
+
+define NUM_COLUMNS  = 8;
+define NUM_ROWS     = 8;
+
+define CUBE_WIDTH   = 40;
+define CUBE_HEIGHT  = 40;
+
+define TETRIS_PORT = 7779;
+
+struct Piece
+{
+   int w, h;
+   int x0, x1;
+   byte data[9];
+};
+
+static Piece pieces[7] =
+{
+   {
+      4, 1, -1, 1,
+      {
+         1,1,1,1
+      }
+   },
+   {
+      3, 2, 0, 0,
+      {
+        4,4,4,
+        4,0,0
+      }
+   },
+   {
+      3, 2, 0, 0,
+      {
+         3,3,3,
+         0,0,3
+      }
+   },
+   {
+      3, 2, 0, 0,
+      {
+         5,5,0,
+         0,5,5
+      }
+   },
+   {
+      3, 2, 0, 0,
+      {
+         0,1,1,
+         1,1,0
+      }
+   },
+   {
+      2, 2, 0, 0,
+      {
+         2,2,
+         2,2
+      }
+   },
+   {
+      3, 2, 0, 0,
+      {
+         2,2,2,
+         0,2,0
+      }
+   }
+};
+
+define MSG_NEWGAME  = 1;
+define MSG_POSITION = 2;
+
+typedef struct
+{
+   byte type;
+   byte player,x,y;
+} TPacket;
+
+define WIDTH  = 12;
+define HEIGHT = 22;
+
+// --- Main Function ---
+class TetrisApp : GuiApplication
+{
+   appName = "ECERE Tetris";
+}
+
+Tetris tetris { };
+
+TetrisService service { };
+
+class TetrisService : Service
+{
+   port = TETRIS_PORT;
+   Tetris tetris;
+   void OnAccept()
+   {
+      if(!tetris.sockets[CLIENT] && !tetris.gameRunning)
+      {
+         TetrisSocket socket { this };
+         TPacket packet;
+
+         tetris.sockets[CLIENT] = socket;
+         packet.type = MSG_NEWGAME;
+         tetris.sockets[CLIENT].Send((byte *)&packet, sizeof(TPacket));
+         tetris.NewGame();
+         tetris.gameRunning = true;
+         tetris.EnableButtons();
+         tetris.Update(null);
+      }
+   }
+}
+
+class TetrisSocket : Socket
+{
+   // --- Tetris Communication ---
+   Tetris tetris;
+   static void OnDisconnect(int code)
+   {
+      if(this == tetris.sockets[CLIENT])
+      {
+         tetris.sockets[CLIENT] = null;
+         tetris.gameRunning = false;
+      }
+      else if(this == tetris.sockets[SERVER])
+      {
+         tetris.sockets[SERVER] = null;
+         tetris.gameRunning = false;
+      }
+
+      tetris.EnableButtons();
+      tetris.Update(null);
+   }
+
+   uint OnReceive(const byte * buffer, uint count)
+   {
+      if(count >= sizeof(TPacket))
+      {
+         TPacket packet = *(TPacket *)buffer;
+         switch(packet.type)
+         {
+            case MSG_POSITION:
+               break;
+            case MSG_NEWGAME:
+               tetris.gameRunning = true;
+               tetris.NewGame();
+               break;
+         }
+         return sizeof(TPacket);
+      }
+      return 0;
+   }
+
+   void OnConnect()
+   {
+      tetris.sockets[SERVER] = this;
+      tetris.gameRunning = true;
+      tetris.EnableButtons();
+      tetris.NewGame();
+   }
+}
+
+class Tetris : Window
+{
+   text = "ECERE Tetris";
+   hasClose = true;
+   clientSize = { 300, 420 };
+
+   Button host
+   {
+      this, text = "Host", position = { 10, 360 }, size = { 60, 20 };
+      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+      {
+         if(service.Start())
+         {
+            hosting = true;
+            EnableButtons();
+            Update(null);
+         }
+         return true;
+      }
+
+   };
+   Button stop
+   {
+      this, text = "Stop", position = { 80, 360 }, size = { 60, 20 };
+
+      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+      {
+         hosting = false;
+         service.Stop();
+         EnableButtons();
+         Update(null);
+         return true;
+      }
+   };
+   Button join
+   {
+      this, text = "Join", position = { 10, 380 }, size = { 40, 20 };
+
+      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+      {
+         TetrisSocket socket { tetris = this };
+         sockets[SERVER] = socket;
+         socket.Connect(address.contents, TETRIS_PORT);
+         EnableButtons();
+         Update(null);
+         return true;
+      }
+   };
+   Button disconnect
+   {
+      this, text = "Disconnect", position = { 170, 370 }, size = { 100, 20 };
+
+      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+      {
+         sockets[SERVER].Disconnect(0);
+         Update(null);
+         return true;
+      }
+   };
+   EditBox address
+   {
+      this, disabled = true, position = { 60, 380 }, size = { 100, 20 }, contents = "localhost";
+   };
+
+   bool hosting, gameRunning, local;
+   byte turn;
+   Bitmap squares[5];
+   Bitmap backgroundBmp { };
+   Socket sockets[2];
+   byte board[HEIGHT][WIDTH];
+   bool gameOver;
+   int angle;
+   int playerx, playery;
+   int newpiece;
+   int nextAngle, nextPiece;
+
+   background = black;
+   tabCycle = true;
+
+   // --- Tetris Utilities ---
+
+   void NewGame()
+   {
+      int x,y;
+      gameOver = false ;
+      for(y = 0; y<HEIGHT; y++)
+         for(x = 0; x<WIDTH; x++)
+            board[y][x] = 0;
+      turn = CLIENT;
+      Update(null);
+      RandomSeed((uint)(GetTime() * 1000));
+      nextPiece = GetRandom(0, 6);
+      nextAngle = GetRandom(0, 3);
+      NewPiece();
+   }
+
+   void EnableButtons()
+   {
+      join.disabled = false;
+      host.disabled = false;
+      disconnect.disabled = false;
+      stop.disabled = false;
+      
+      if(!hosting)
+         stop.disabled = true;
+      if(!sockets[SERVER])
+         disconnect.disabled = true;
+
+      if(hosting || sockets[SERVER])
+         host.disabled = true;
+         
+      if(sockets[CLIENT] || hosting)
+         join.disabled = true;
+
+      // address.disabled = join.disabled;
+   }
+
+   // --- Tetris Window Class ---
+
+   void OnRedraw(Surface surface)
+   {
+      // Background...
+      surface.Blit(backgroundBmp, 0,0, 0,0, backgroundBmp.width, backgroundBmp.height);
+
+      //if(GameRunning)
+      {
+         Piece * piece = &pieces[newpiece];
+         int x,y;
+         for(x = 0; x<WIDTH; x++)
+         {
+            for(y = 0; y<HEIGHT; y++)
+            {
+               int square = board[y][x];
+               if(square)
+                  surface.Blit(squares[square-1], x * 16, y * 16, 0, 0, 16, 16);
+            }
+         }
+         if(!gameOver)
+         {
+            for(x = 0; x<piece->w; x++)
+               for(y = 0; y<piece->h; y++)
+               {
+                  int square;
+                  int rx, ry;
+
+                  switch(angle)
+                  {
+                     case 0: rx = x; ry = y; break;
+                     case 1: rx = piece->h-1 - y; ry = x; break;
+                     case 2: rx = piece->w-1 - x; ry = piece->h -1- y; break;
+                     case 3: rx = y; ry = piece->w-1 - x; break;
+                  }
+
+                  switch(angle)
+                  {
+                     case 0: case 2: rx += piece->x0; break;
+                     case 1: case 3: rx += piece->x1; break;
+                  }
+                  
+                  square = piece->data[y * piece->w + x];
+                  if(square)
+                     surface.Blit(squares[square-1], (rx + playerx) * 16, (ry + playery) * 16, 0, 0, 16, 16);
+               }
+         }
+         piece = &pieces[nextPiece];
+         for(x = 0; x<piece->w; x++)
+            for(y = 0; y<piece->h; y++)
+            {
+               int square;
+               int rx, ry;
+
+               switch(nextAngle)
+               {
+                  case 0: rx = x; ry = y; break;
+                  case 1: rx = piece->h-1 - y; ry = x; break;
+                  case 2: rx = piece->w-1 - x; ry = piece->h -1- y; break;
+                  case 3: rx = y; ry = piece->w-1 - x; break;
+               }
+
+               switch(nextAngle)
+               {
+                  case 0: case 2: rx += piece->x0; break;
+                  case 1: case 3: rx += piece->x1; break;
+               }
+               
+               square = piece->data[y * piece->w + x];
+               if(square)
+                  surface.Blit(squares[square-1], rx * 16 + (WIDTH + 2) * 16, ry * 16 + 10, 0, 0, 16, 16);
+            }
+      }
+   }
+
+   bool OnCreate()
+   {
+      playerx = 5;
+      NewGame();
+      EnableButtons();
+      return true;
+   }
+
+   void OnDestroy()
+   {
+      if(sockets[0]) sockets[0].OnDisconnect = null;
+      if(sockets[1]) sockets[1].OnDisconnect = null;
+   }
+
+   bool OnLoadGraphics()
+   {
+      int c;
+      Bitmap tetrisBlocks { };
+      if(tetrisBlocks.Load(":tetris.bmp", null, null))
+      {
+         for(c=0; c<5; c++)
+         {
+            if(!squares[c]) squares[c] = Bitmap { };
+            squares[c].Allocate(null, 16,16,16, pixelFormat888, false);
+            squares[c].Grab(tetrisBlocks, c*16, 0);
+            squares[c].MakeDD(displaySystem);
+         }
+
+         backgroundBmp.Allocate(null, 192,352,192, pixelFormat888, false);
+         backgroundBmp.Grab(tetrisBlocks, 0, 24);
+         backgroundBmp.MakeDD(displaySystem);
+      }
+      delete tetrisBlocks;
+      return true;
+   }
+
+   void OnUnloadGraphics()
+   {
+      int c;
+      for(c=0; c<5; c++)
+         squares[c].Free();
+      backgroundBmp.Free();
+   }
+
+   bool OnKeyDown(Key key, unichar ch)
+   {
+      switch(key)
+      {
+         case escape:
+            Destroy(0);
+            break;
+      }
+      return true;
+   }
+
+   void NewPiece()
+   {
+      newpiece = nextPiece;
+      angle = nextAngle;
+      playerx = 5;
+      playery = 0;
+      if(CheckPiece())
+      {
+         gameOver = true;
+      }
+      else
+      {
+         nextPiece = GetRandom(0, 6);
+         nextAngle = GetRandom(0, 3);
+      }
+   }
+
+   void FreezePiece()
+   {
+      Piece * piece = &pieces[newpiece];
+      int x,y;
+      int numLines = 0;
+      for(x = 0; x<piece->w; x++)
+      {
+         for(y = 0; y<piece->h; y++)
+         {
+            int square;
+            int rx, ry;
+
+            switch(angle)
+            {
+               case 0: rx = x; ry = y; break;
+               case 1: rx = piece->h-1 - y; ry = x; break;
+               case 2: rx = piece->w-1 - x; ry = piece->h -1- y; break;
+               case 3: rx = y; ry = piece->w-1 - x; break;
+            }
+
+            switch(angle)
+            {
+               case 0: case 2: rx += piece->x0; break;
+               case 1: case 3: rx += piece->x1; break;
+            }
+            square = piece->data[y * piece->w + x];
+            if(square)
+               board[ry + playery][rx + playerx] = (byte)square;
+         }
+      }
+      for(y = HEIGHT - 1; y >= 0; y--)
+      {
+         for(x = 0; x < WIDTH; x++)
+         {
+            if(!board[y][x]) break;
+         }
+         if(x == WIDTH)
+         {
+            numLines++;
+            if(y > 0)
+               memmove(&board[1], &board, y * WIDTH);
+            memset(&board, 0, WIDTH);
+            y++;
+         }  
+      }
+
+      NewPiece();
+   }
+
+   void DropPiece()
+   {
+      while(!CheckPiece())
+      {
+         playery++;
+      }
+      playery--;
+      FreezePiece();  
+   }
+
+   bool CheckPiece()
+   {
+      Piece * piece = &pieces[newpiece];
+      bool result = false;
+      if(((angle == 0 || angle == 2) ? piece->h : piece->w) + playery > HEIGHT)
+      {
+         //playery = HEIGHT - ((angle == 0 || angle == 2) ? piece->h : piece->w);
+         result = true;
+      }
+      if(!result)
+      {
+         int x,y;
+         for(x = 0; x<piece->w && !result; x++)
+            for(y = 0; y<piece->h && !result; y++)
+            {
+               int square;
+               int rx, ry;
+
+               switch(angle)
+               {
+                  case 0: rx = x; ry = y; break;
+                  case 1: rx = piece->h-1 - y; ry = x; break;
+                  case 2: rx = piece->w-1 - x; ry = piece->h -1- y; break;
+                  case 3: rx = y; ry = piece->w-1 - x; break;
+               }
+
+               switch(angle)
+               {
+                  case 0: case 2: rx += piece->x0; break;
+                  case 1: case 3: rx += piece->x1; break;
+               }
+               square = piece->data[y * piece->w + x];
+               if(square && board[ry + playery][rx + playerx])
+               {
+                  //playery--;
+                  result = true;
+               }
+            }
+      }
+      /*if(result)
+         FreezePiece();*/
+      return result;
+   }
+
+   bool OnKeyHit(Key key, unichar ch)
+   {
+      Piece * piece = &pieces[newpiece];
+      if(!gameOver)
+      {
+         switch(key)
+         {
+            case left:
+            case right:
+               if(key == left) playerx--; else playerx++;
+               playerx = Max(playerx, -((angle == 0 || angle == 2) ? (piece->x0) : (piece->x1)));
+               playerx = Min(playerx, 12 - ((angle == 0 || angle == 2) ? (piece->x0 + piece->w) : (piece->x1 + piece->h)));
+               if(CheckPiece())
+               {
+                  if(key == left) playerx++; else playerx--;               
+               }
+               break;
+            case down:
+               playery++;
+               if(CheckPiece())
+               {
+                  playery--;
+                  FreezePiece();
+               }
+               break;
+            case up: 
+            {
+               int oldx = playerx;
+               angle++;
+               if(angle>3) angle = 0;
+               playerx = Max(playerx, -((angle == 0 || angle == 2) ? (piece->x0) : (piece->x1)));
+               playerx = Min(playerx, 12 - ((angle == 0 || angle == 2) ? (piece->x0 + piece->w) : (piece->x1 + piece->h)));
+
+               if(CheckPiece())
+               {
+                  angle--;
+                  if(angle < 0) angle += 4;
+                  playerx = oldx;
+               }
+               break;
+            }
+            case space:
+            {
+               DropPiece();
+               break;
+            }
+         }
+         Update(null);
+      }
+      return true;
+   }
+
+   bool OnLeftButtonDown(int x, int y, Modifiers mods)
+   {
+      x /= CUBE_WIDTH;
+      y /= CUBE_HEIGHT;
+
+      if(sockets[1-turn])
+      {
+         if(x < NUM_COLUMNS && y < NUM_ROWS)
+         {
+            TPacket packet;
+            packet.type = MSG_POSITION;
+            packet.player = turn;
+            packet.x = (byte)x;
+            packet.y = (byte)y;
+            sockets[turn].Send((byte *)&packet, sizeof(TPacket));
+         }
+      }
+      return true;
+   }
+}
diff --git a/samples/games/tetris/tetris.epj b/samples/games/tetris/tetris.epj
new file mode 100644 (file)
index 0000000..ae72139
--- /dev/null
@@ -0,0 +1,79 @@
+
+ECERE Project File
+
+Version 0.1a
+
+Target "tetris"
+
+   Configurations
+
+    + Debug
+
+         Compiler Options
+
+            Intermediate Directory = debug
+            Debug = True
+            Optimize = None
+            Profile = False
+            MemoryGuard = False
+            AllWarnings = True
+            Strict Name Spaces = False
+
+         Linker Options
+
+            Target Name = tetris
+            Target Type = Executable
+            Target Directory = debug
+            Console = False
+
+            Libraries = ecere
+
+    + Release
+
+         Compiler Options
+
+            Intermediate Directory = release
+            Debug = False
+            Optimize = Speed
+            Profile = False
+            MemoryGuard = False
+            AllWarnings = True
+            Strict Name Spaces = False
+
+         Linker Options
+
+            Target Name = tetris
+            Target Type = Executable
+            Target Directory = release
+            Console = False
+
+            Libraries = ecere
+
+    + memguard
+
+         Compiler Options
+
+            Intermediate Directory = memguard
+            Debug = True
+            Optimize = None
+            Profile = False
+            MemoryGuard = True
+            AllWarnings = True
+            Strict Name Spaces = False
+
+         Linker Options
+
+            Target Name = tetris
+            Target Type = Executable
+            Target Directory = memguard
+            Console = False
+
+            Libraries = memguard
+
+   Files
+
+    - tetris.ec
+
+   Resources
+
+    = data/tetris.bmp
diff --git a/samples/games/tongIts/tongIts.epj b/samples/games/tongIts/tongIts.epj
new file mode 100644 (file)
index 0000000..2c8fcc3
--- /dev/null
@@ -0,0 +1,31 @@
+
+ECERE Project File
+
+Version 0a
+
+Target "tongIts"
+
+   Compiler Options
+
+      Intermediate Directory = obj
+      Debug = True
+      Optimize = False
+      Profile = False
+      AllWarnings = False
+
+   Linker Options
+
+      Target Name = tongIts
+      Target Type = Executable
+      Console = False
+
+      Libraries = ecere
+
+   Files
+
+    - tongits.ec
+
+   Resources
+
+    = data/ecereCard.bmp
+    = data/cards.pcx
diff --git a/samples/games/tongIts/tongits.ec b/samples/games/tongIts/tongits.ec
new file mode 100644 (file)
index 0000000..d377a40
--- /dev/null
@@ -0,0 +1,790 @@
+import "ecere"
+
+#define MCARD(k,n) ((n) * 4 + (k))
+#define NUMBER(id) ((id) / 4)
+#define KIND(id)   ((id) % 4)
+#define OFFSETTER1   15
+#define OFFSETTER2   120
+#define HOUSETYPE_STRAIGHT 0
+#define HOUSETYPE_KIND     1
+
+typedef struct
+{
+   int typeOfHouse;
+   
+   union
+   {
+      struct straight
+      {
+         int first, last;
+         int suit;
+      } straight;
+      struct kind
+      {
+         int number;
+         bool suits[4];
+      } kind;
+   };
+} House;
+
+typedef struct
+{
+   int numCards;
+   int cardValues[13];
+   House houseDown[4]; 
+   int numHouseDown;
+   bool cardLifted[13];
+   bool callTag;
+} Player;
+
+int cards[52];
+int discard[28];
+int discardCounter = 0;
+int deckCounter = 0;
+int numOfPlayers = 4;
+int currentPlayer = 0;
+int cardToReposition = 0;
+int xMouseMove=0,yMouseMove=0,xLeftButtonUp=0,yLeftButtonUp=0;
+int xCursorPositionAtCard=0,yCursorPositionAtCard=0,width=0,height=0;
+int dragCard = -1;
+Player player[4];
+Point xyPositions[4] =
+{
+   {30,150},
+   {30,500},
+   {600,500},
+   {600,150}
+};
+
+bool flagButtonDown, leftDoubleClick, gameOver;
+
+//player[0].houseDown[0].straight.suit
+
+void NewDeckOfCards()
+{
+   int i;
+   for(i=0;i<52;i++)
+   {
+      cards[i]=i;
+   }
+}
+
+void Shuffle()
+{
+   int i,j,randNum;
+   for(i=0;i<52;i++)
+   {
+      randNum = GetRandom(0,51);
+      j=cards[i];
+      cards[i]=cards[randNum];
+      cards[randNum]=j;
+   }
+}
+
+void DealCards(int numPlayers)
+{
+   int c, p;
+
+   player[0].cardValues[player[0].numCards++] = cards[deckCounter++];
+   for(c = 0; c<((numPlayers > 3) ? 9 : 12); c++)
+      for(p = 0; p<numPlayers; p++)
+         player[(p+1)%numPlayers].cardValues[player[(p+1)%numPlayers].numCards++] = cards[deckCounter++];
+   //player[0].houseDown[0].straight.suit
+}
+
+int CheckHouse(int cardsToCheck,int * checkIfHouse)
+{
+   int i,straight=0,house=0;
+   for(i=cardsToCheck-1;i>=0;i--)
+   {
+      if(checkIfHouse[i] == checkIfHouse[i-1] + 4)
+      {
+         straight++;  //possible straight house
+      }
+      else if(NUMBER(checkIfHouse[i]) == NUMBER(checkIfHouse[i-1]))
+      {
+         house++;    //possible 3or4 of a kind house
+      }
+   }     
+   if(straight == cardsToCheck-1)
+      return 0;
+   else if(house == cardsToCheck-1)
+      return 1;
+   else
+      return -1;
+}
+
+int CompareInteger(int * a, int * b)
+{
+   if(*a > *b) 
+      return 1;
+   else if(*b > *a)
+      return -1;
+   else return 0;
+}
+
+void SortPlayerCards()
+{
+   int c;
+   for(c=0;c<numOfPlayers;c++)
+   {
+      qsort(player[c].cardValues,player[c].numCards,sizeof(int),CompareInteger); 
+      //qsort(tempHouse,tempCtr,sizeof(int),CompareInteger);
+   }
+}
+
+class TongIts : Window
+{
+   Bitmap bitmapCards[52];
+   Bitmap cardBack {};
+   Button drawButton[4], chowButton[4], dumpButton[4], callButton[4], showButton[4], doneButton[4];
+
+   hasClose = true;
+   hasMinimize = true;
+   hasMaximize = true;
+   background = Color { 113,156,169 };
+   borderStyle = sizable;
+   text = "Tong-Its";
+   size = Size { 900,700 };
+
+   bool OnCreate()
+   {
+      int c;
+      RandomSeed((int)(GetTime() * 1000));
+      NewDeckOfCards();
+      Shuffle();
+      DealCards(numOfPlayers);
+      SortPlayerCards();
+      for(c = 0; c<numOfPlayers; c++)
+      {
+         drawButton[c] = Button { this, text = "Draw Card", position = xyPositions[c], size = Size { 80,20 }, id = c*6, disabled = true, NotifyClicked = DrawClicked };
+         chowButton[c] = Button { this, text = "Chow", position = Point { xyPositions[c].x + 80,xyPositions[c].y }, size = Size { 80,20 }, id = c*6, disabled = true, NotifyClicked = ChowClicked };
+         dumpButton[c] = Button { this, text = "Dump", position = Point { xyPositions[c].x + 160, xyPositions[c].y }, size = Size { 80,20 }, id = c*6, disabled = true, NotifyClicked = DumpClicked };
+         callButton[c] = Button { this, text = "Call", position = Point { xyPositions[c].x, xyPositions[c].y + 20 }, size = Size { 80,20 }, id = c*6, disabled = true, NotifyClicked = CallClicked };
+         showButton[c] = Button { this, text = "Show", position = Point { xyPositions[c].x + 80, xyPositions[c].y + 20 }, size = Size { 80,20 }, id = c*6, disabled = true, NotifyClicked = ShowClicked };
+         doneButton[c] = Button { this, text = "Done", position = Point { xyPositions[c].x + 160, xyPositions[c].y + 20 },size = Size { 80,20 }, id = c*6, disabled = true, NotifyClicked = DoneClicked };
+      }
+      showButton[currentPlayer].disabled = false;
+      dumpButton[currentPlayer].disabled = false;
+      return true;
+   }
+
+   bool OnLoadGraphics()
+   {
+      int i;
+      Bitmap ptrCardLoad {};
+      ptrCardLoad.Load(":cards.pcx",null,null);
+      cardBack.LoadT(":ecereCard.bmp", null, displaySystem);
+      
+      for(i=0;i<52;i++)
+      {
+         Bitmap bitmap { transparent = true };
+         bitmap.Allocate(null,ptrCardLoad.width, ptrCardLoad.height/52,0,pixelFormat8,true);
+         CopyBytesBy4(bitmap.palette, ptrCardLoad.palette, 256);
+         bitmap.Grab(ptrCardLoad,0,(ptrCardLoad.height/52)*i);
+         bitmap.MakeDD(displaySystem);
+         bitmapCards[i] = bitmap;
+      }
+      delete ptrCardLoad;
+      return true;
+   }
+
+   void OnUnloadGraphics()
+   {
+      int i;
+      for(i=0;i<52;i++)
+         bitmapCards[i].Free();
+   }
+   
+   void GameOver()
+   {
+      /*
+      Window gameOverBox
+      { 
+         this, hasClose = true, background = LightBlue, text = "Game Over", [position.y] = A_CENTER|20, size = Size { 300, 200 }
+      };
+      Button { gameOverBox, text = "Close", [position.y] = A_CENTER|80, size = Size { 80,20 } };
+      */
+      gameOver = true;
+   }
+
+   void OnRedraw(Surface surface)
+   {
+      int h=0,i=0,j=0,k=0,x=0;
+
+      surface.Rectangle(375, 315, 495, 475);
+   
+      if(gameOver)
+      {
+         surface.SetForeground(blue);
+         surface.SetBackground(red);
+   //      surface.Area(375,100,495,150);
+         surface.Area(375,370,495,420);
+         //surface.TextOpacity(true);
+   //      surface.WriteTextf(398, 115,"GAME OVER");
+         surface.WriteTextf(398, 385,"GAME OVER");
+      }
+
+      for(i=deckCounter,x=0;i<52;i+=5,x+=2)
+      {
+         Bitmap bitmap = cardBack;
+         surface.Blit(bitmap,400 + x, 195 + x,0,0, bitmap.width,bitmap.height);
+      }
+
+      if(discardCounter > 0)
+      {
+         Bitmap bitmap = bitmapCards[discard[discardCounter-1]];
+         surface.Blit(bitmap, xLeftButtonUp, yLeftButtonUp,0,0, bitmap.width,bitmap.height);
+      }
+
+      for(j=0;j<numOfPlayers;j++)
+      {
+         for(i=0;i<player[j].numCards;i++)
+         {
+            if(player[j].cardValues[i] != dragCard || (!flagButtonDown))
+            {
+               Bitmap bitmap = bitmapCards[player[j].cardValues[i]];
+               if(player[j].cardLifted[i])
+               {
+                  surface.Blit(bitmap,xyPositions[j].x + OFFSETTER1 * i,xyPositions[j].y - OFFSETTER2 - 20,0,0, bitmap.width,bitmap.height);
+               }
+               else
+               {
+                  surface.Blit(bitmap,xyPositions[j].x + OFFSETTER1 * i,xyPositions[j].y - OFFSETTER2,0,0, bitmap.width,bitmap.height);
+               }
+            }
+         }
+         for(i=0,h=0;i<player[j].numHouseDown;i++,h++)
+         {
+            if(player[j].houseDown[i].typeOfHouse == 0)
+            {
+               for(k=player[j].houseDown[i].straight.first;k<=player[j].houseDown[i].straight.last;k++)
+               {
+                  Bitmap bitmap = bitmapCards[MCARD((player[j].houseDown[i].straight.suit),(k))];
+                  surface.Blit(bitmap,xyPositions[j].x + OFFSETTER1 * h,xyPositions[j].y + 75,0,0, bitmap.width,bitmap.height);
+                  h++;
+               }
+            }
+            
+            if(player[j].houseDown[i].typeOfHouse == 1)
+            {
+               for(k=0;k<4;k++) //player[j].houseDown[i].kind.suits[k]
+               {
+                  if(player[j].houseDown[i].kind.suits[k] == true)   
+                  {
+                     Bitmap bitmap = bitmapCards[MCARD((k),(player[j].houseDown[i].kind.number))];
+                     surface.Blit(bitmap,xyPositions[j].x + OFFSETTER1 * h,xyPositions[j].y + 75,0,0, bitmap.width,bitmap.height);
+                     h++;
+                  }  //_2D xyPositions[4] = {{30,150},{30,500},{540,500},{540,150}};
+               }
+            }
+         }
+      }
+      if(flagButtonDown)
+      {
+         for(i=0;i<player[currentPlayer].numCards;i++)
+         {
+            Bitmap bitmap = bitmapCards[player[currentPlayer].cardValues[i]];
+            if(player[currentPlayer].cardValues[i] == dragCard)
+            {
+               surface.Blit(bitmap,xMouseMove + xCursorPositionAtCard,yMouseMove + yCursorPositionAtCard,0,0, bitmap.width,bitmap.height);
+            }
+         }
+      }
+      if(gameOver)
+      {
+         surface.SetForeground(blue);
+         surface.SetBackground(red);
+   //      surface.Area(375,100,495,150);
+         surface.Area(375,370,495,420);
+         //surface.TextOpacity(true);
+   //      surface.WriteTextf(398, 115,"GAME OVER");
+         surface.WriteTextf(398, 385,"GAME OVER");
+         for(i=0;i<numOfPlayers;i++)
+         {
+            drawButton[i].disabled = true;
+            chowButton[i].disabled = true;
+            dumpButton[i].disabled = true;
+            callButton[i].disabled = true;
+            showButton[i].disabled = true;
+            doneButton[i].disabled = true;
+         }
+   //      eWindow_Create("MessageBox",MSGBOX_OK,ES_CAPTION,window,null,A_LEFT,A_RIGHT,200,100,0,null,0,null,0);
+      }
+   /*      if(j == 1)
+         {
+            for(i=0;i<player[j].numCards;i++)
+            {
+               Bitmap bitmap = bitmapCards[MCARD(KIND(player[2].cardValues[i]),NUMBER(player[2].cardValues[i]))];
+               surface.Blit(bitmap,30+15*i,500,0,0, bitmap.width,bitmap.height);
+            }
+         }
+         else
+         {
+            for(i=0;i<player[j].numCards;i++)
+            {
+               //Bitmap bitmap1 = bitmapCards[MCARD(KIND(player[1].cardValues[i]),NUMBER(player[1].cardValues[i]))];
+               Bitmap bitmap = cardBack;
+               surface.Blit(bitmap,30+15*i,30+nextLane,0,0, bitmap.width,bitmap.height);
+            }
+         }
+      }*/
+   }
+
+   bool DrawClicked(Button button, int x, int y, Modifiers mods)
+   {
+      player[currentPlayer].cardValues[player[currentPlayer].numCards++] = cards[deckCounter++];
+      drawButton[currentPlayer].disabled = true;
+      chowButton[currentPlayer].disabled = true;
+      callButton[currentPlayer].disabled = true;
+      showButton[currentPlayer].disabled = false;
+      dumpButton[currentPlayer].disabled = false;
+      Update(null);
+      return true;
+   }
+
+   bool ChowClicked(Button button, int x, int y, Modifiers mods)
+   {
+      int i, j, suit, number;
+      int tempCtr = 0;
+      int tempHouse[13];
+      for(i=0;i<13;i++)
+      {
+         tempHouse[i]=0;
+      }
+      suit = KIND(discard[discardCounter-1]);
+      number = NUMBER(discard[discardCounter-1]);
+      tempHouse[tempCtr++] = discard[discardCounter-1];  
+      for(i=0;i<player[currentPlayer].numCards;i++)
+      {
+         if(player[currentPlayer].cardLifted[i])
+         {
+            tempHouse[tempCtr++] = player[currentPlayer].cardValues[i];
+         }
+      }
+      if(tempCtr >= 3)
+      {
+         int checkResult;
+         
+         qsort(tempHouse,tempCtr,sizeof(int),CompareInteger);
+         checkResult = CheckHouse(tempCtr,tempHouse);
+         switch(checkResult)
+         {
+            // 3/4 of a kind
+            case 1:
+            {
+               House * house = &player[currentPlayer].houseDown[player[currentPlayer].numHouseDown];
+               house->typeOfHouse = checkResult;
+               for(i=0;i<tempCtr;i++)
+               {  
+                  house->kind.number = NUMBER(tempHouse[i]);
+                  house->kind.suits[KIND(tempHouse[i])] = true;  
+               }   
+               player[currentPlayer].numHouseDown++;
+               break;
+            }
+            case 0:
+            {
+               House * house = &player[currentPlayer].houseDown[player[currentPlayer].numHouseDown];
+               house->typeOfHouse = checkResult;
+               house->straight.first = NUMBER(tempHouse[0]);
+               house->straight.last = NUMBER(tempHouse[tempCtr-1]);
+               house->straight.suit = KIND(tempHouse[0]);  
+               player[currentPlayer].numHouseDown++;
+               break;
+            }
+            case -1:
+            {
+               return true;
+               break;
+            }
+         }
+         for(i=0,j=0;i<player[currentPlayer].numCards;i++)
+         {
+            if(!player[currentPlayer].cardLifted[i])
+            {
+               player[currentPlayer].cardValues[j] = player[currentPlayer].cardValues[i];
+               player[currentPlayer].cardLifted[j] = false;
+               j++;
+            }
+         }
+         player[currentPlayer].numCards = j;   
+         discard[discardCounter--];
+         drawButton[currentPlayer].disabled = true;
+         chowButton[currentPlayer].disabled = true;
+         callButton[currentPlayer].disabled = true;
+         showButton[currentPlayer].disabled = false;
+         dumpButton[currentPlayer].disabled = false;
+         Update(null);    
+      }
+     if(player[currentPlayer].numCards == 0)
+     {
+         GameOver();
+     }
+     return true;
+  }
+
+   bool DumpClicked(Button button, int x, int y, Modifiers mods)
+   {  
+      MessageBox { text = button.text }.Create();
+      return true;
+   }
+
+   bool CallClicked(Button button, int x, int y, Modifiers mods)
+   {
+      MessageBox { text = button.text }.Create();
+      return true;
+   }
+
+   bool ShowClicked(Button button, int x, int y, Modifiers mods)
+   {
+      int i, j;
+      int tempHouse[13];
+      int tempCtr = 0;
+      for(i=0;i<13;i++)
+      {
+         tempHouse[i]=0;
+      }
+      for(i=0;i<player[currentPlayer].numCards;i++)
+      {
+         if(player[currentPlayer].cardLifted[i])
+         {
+            tempHouse[tempCtr++] = player[currentPlayer].cardValues[i];
+         }
+      }
+      if(tempCtr >= 3)
+      {
+         int checkResult;
+         qsort(tempHouse,tempCtr,sizeof(int),CompareInteger);
+         checkResult = CheckHouse(tempCtr,tempHouse);
+         switch(checkResult)
+         {
+            // 3/4 of a kind
+            case 1:
+            {
+               House * house = &player[currentPlayer].houseDown[player[currentPlayer].numHouseDown];
+               house->typeOfHouse = checkResult;
+               for(i=0;i<tempCtr;i++)
+               {  
+                  house->kind.number = NUMBER(tempHouse[i]);
+                  house->kind.suits[KIND(tempHouse[i])] = true;  
+               }   
+               player[currentPlayer].numHouseDown++;
+               break;
+            }
+            case 0:
+            {
+               House * house = &player[currentPlayer].houseDown[player[currentPlayer].numHouseDown];
+               house->typeOfHouse = checkResult;
+               house->straight.first = NUMBER(tempHouse[0]);
+               house->straight.last = NUMBER(tempHouse[tempCtr-1]);
+               house->straight.suit = KIND(tempHouse[0]);  
+               player[currentPlayer].numHouseDown++;
+               break;
+            }
+            case -1:
+            {
+               return true; //false;
+               break;
+            }
+         }
+         for(i=0,j=0;i<player[currentPlayer].numCards;i++)
+         {
+            if(!player[currentPlayer].cardLifted[i])
+            {
+               player[currentPlayer].cardValues[j] = player[currentPlayer].cardValues[i];
+               player[currentPlayer].cardLifted[j] = false;
+               j++;
+            }
+         }
+         player[currentPlayer].numCards = j;   
+         if(player[currentPlayer].numCards == 0)
+         {
+            GameOver();
+         }
+         Update(null);    
+      }
+      return true;
+   }
+
+   bool DoneClicked(Button button, int x, int y, Modifiers mods)
+   {
+      MessageBox { text = button.text }.Create();
+      return true;
+   }
+
+   bool OnMouseMove(int x, int y, Modifiers mods)
+   {
+      if(flagButtonDown)
+      {
+         xMouseMove = x;
+         yMouseMove = y;
+         Capture();
+         Update(null);
+      }
+      return true;
+   }
+
+   bool OnLeftButtonDown(int x, int y, Modifiers mods)
+   {
+      int i;
+      if(!gameOver)
+      {
+         for(i=player[currentPlayer].numCards-1;i>=0;i--)
+         {
+            Bitmap bitmap = bitmapCards[player[currentPlayer].cardValues[i]];
+            if(Box {
+               xyPositions[currentPlayer].x + (OFFSETTER1 * i),
+               (player[currentPlayer].cardLifted[i] ? (xyPositions[currentPlayer].y - OFFSETTER2 - 20) :( xyPositions[currentPlayer].y - OFFSETTER2)),
+               bitmap.width + (xyPositions[currentPlayer].x + OFFSETTER1 * i),
+               bitmap.height + (player[currentPlayer].cardLifted[i] ? (xyPositions[currentPlayer].y - OFFSETTER2 - 20) : (xyPositions[currentPlayer].y - OFFSETTER2))
+               }.IsPointInside(Point { x, y }) && drawButton[currentPlayer].disabled)
+            {
+               dragCard = player[currentPlayer].cardValues[i];
+               cardToReposition = i;
+               width = bitmap.width;
+               height = bitmap.height;
+               xCursorPositionAtCard = (xyPositions[currentPlayer].x + (OFFSETTER1 * i)) - x;
+               yCursorPositionAtCard = (player[currentPlayer].cardLifted[i] ? 
+                  (xyPositions[currentPlayer].y - OFFSETTER2 - y - 20) : 
+                  (xyPositions[currentPlayer].y - OFFSETTER2 - y));
+               flagButtonDown = true;
+               OnMouseMove(x,y,mods);
+               break;
+            }
+         }
+      }
+      return true;
+   }
+
+   bool OnLeftButtonUp(int x, int y, Modifiers mods)
+   {
+      int h,i,j;
+      Box boxDiscard={375, 315, 495, 475};
+      Box boxCard = {x + xCursorPositionAtCard,y + yCursorPositionAtCard, x + xCursorPositionAtCard + width - 1, y + yCursorPositionAtCard + height - 1};
+      if(flagButtonDown)
+      {
+         if(boxCard.Overlap(boxDiscard))      
+         {
+            xLeftButtonUp = 400;
+            yLeftButtonUp = 350;
+            CopyBytesBy4(&player[currentPlayer].cardValues[cardToReposition],
+               &player[currentPlayer].cardValues[cardToReposition+1],
+               player[currentPlayer].numCards-1-cardToReposition);
+            player[currentPlayer].numCards--;
+            discard[discardCounter++] = dragCard;
+            if(player[currentPlayer].numCards == 0 || deckCounter == 52)
+            {
+               GameOver();
+            }
+            else
+            {
+               for(i=0;i<player[currentPlayer].numCards;i++)
+               {
+                  player[currentPlayer].cardLifted[i] = false;
+               }
+               drawButton[currentPlayer].disabled = true;
+               chowButton[currentPlayer].disabled = true;
+               dumpButton[currentPlayer].disabled = true;
+               callButton[currentPlayer].disabled = true;
+               showButton[currentPlayer].disabled = true;
+               doneButton[currentPlayer].disabled = true;
+               player[currentPlayer].callTag = false;
+               currentPlayer++;
+               currentPlayer %= numOfPlayers;
+               drawButton[currentPlayer].disabled = false;
+               chowButton[currentPlayer].disabled = false;
+               if(player[currentPlayer].numHouseDown >= 2 && player[currentPlayer].callTag == false)
+                  callButton[currentPlayer].disabled = false;
+            }
+         }
+         else
+         {
+            for(j=0;j<numOfPlayers;j++)
+            {
+               Bitmap bitmap = cardBack;
+               Box boxHouseDown = 
+               { 
+                  xyPositions[j].x,xyPositions[j].y + 75,
+                  0, xyPositions[j].y + 75 + bitmap.height
+               };
+               for(i=0;i<player[j].numHouseDown;i++)
+               {
+                  if(player[j].houseDown[i].typeOfHouse == 0)
+                  {
+                     boxHouseDown.right = boxHouseDown.left + bitmap.width +
+                        (player[j].houseDown[i].straight.last - player[j].houseDown[i].straight.first) * OFFSETTER1 - 1;
+                     if(boxCard.Overlap(boxHouseDown))
+                     {
+                        if(dragCard == MCARD((player[j].houseDown[i].straight.suit),(player[j].houseDown[i].straight.first)) - 4) 
+                        {
+                           player[j].houseDown[i].straight.first --;
+                           CopyBytesBy4(&player[currentPlayer].cardValues[cardToReposition],
+                              &player[currentPlayer].cardValues[cardToReposition+1],
+                              player[currentPlayer].numCards-1-cardToReposition);
+                           player[currentPlayer].numCards--;
+                           player[j].callTag = true;
+                           j = numOfPlayers;
+                           break;
+                           
+                        }
+                        else if(dragCard == MCARD((player[j].houseDown[i].straight.suit),(player[j].houseDown[i].straight.last )) + 4)
+                        {
+                           player[j].houseDown[i].straight.last ++;
+                           CopyBytesBy4(&player[currentPlayer].cardValues[cardToReposition],
+                              &player[currentPlayer].cardValues[cardToReposition+1],
+                              player[currentPlayer].numCards-1-cardToReposition);
+                           player[currentPlayer].numCards--;
+                           player[j].callTag = true;
+                           j = numOfPlayers;
+                           break;
+                        }
+                     }
+                     boxHouseDown.left += 
+                        (player[j].houseDown[i].straight.last - player[j].houseDown[i].straight.first + 2) * OFFSETTER1;
+                  }
+                  else if(player[j].houseDown[i].typeOfHouse == 1)
+                  {
+                     if(player[j].houseDown[i].kind.suits[0] == false || player[j].houseDown[i].kind.suits[1] == false ||
+                        player[j].houseDown[i].kind.suits[2] == false || player[j].houseDown[i].kind.suits[3] == false)
+                     {
+                        h=4;
+                        boxHouseDown.right = boxHouseDown.left + (2 * OFFSETTER1) + bitmap.width - 1;
+                     }
+                     else
+                     {
+                        h=5;
+                     }
+                     if(boxCard.Overlap(boxHouseDown))
+                     {
+                        if(NUMBER(dragCard) == player[j].houseDown[i].kind.number)
+                        {
+                           player[j].houseDown[i].kind.suits[KIND(dragCard)] = true;
+                           CopyBytesBy4(&player[currentPlayer].cardValues[cardToReposition],
+                                 &player[currentPlayer].cardValues[cardToReposition+1],
+                                 player[currentPlayer].numCards-1-cardToReposition);
+                           player[currentPlayer].numCards--;
+                           player[j].callTag = true;
+                           j = numOfPlayers;
+                           break;
+                        }
+                     }
+                     boxHouseDown.left += (h * OFFSETTER1);
+                  }
+               }
+            }
+         }
+         flagButtonDown = false;
+         ReleaseCapture();
+         Update(null);
+      }   
+      return true;
+   }
+
+   bool OnLeftDoubleClick(int x, int y, Modifiers mods)
+   {
+      int i;
+      for(i=player[currentPlayer].numCards-1;i>=0;i--)
+      {
+         Bitmap bitmap = bitmapCards[player[currentPlayer].cardValues[i]];
+
+         if(Box {
+            xyPositions[currentPlayer].x + (OFFSETTER1 * i),
+            (player[currentPlayer].cardLifted[i] ? (xyPositions[currentPlayer].y - OFFSETTER2 - 20) :(xyPositions[currentPlayer].y - OFFSETTER2)),
+            bitmap.width + (xyPositions[currentPlayer].x + OFFSETTER1 * i),
+            bitmap.height + (player[currentPlayer].cardLifted[i] ? (xyPositions[currentPlayer].y - OFFSETTER2 - 20) : (xyPositions[currentPlayer].y - OFFSETTER2))
+            }.IsPointInside(Point{x,y}))
+         {
+            player[currentPlayer].cardLifted[i] ^= true;
+            Update(null);
+            return false;
+         }
+      
+      }
+      return true;
+   }
+
+   bool OnRightButtonDown(int x, int y, Modifiers mods)
+   {
+      int i;
+
+      if(!gameOver)
+      {
+         for(i=player[currentPlayer].numCards-1;i>=0;i--)
+         {
+            Bitmap bitmap = bitmapCards[player[currentPlayer].cardValues[i]];
+            if(Box {
+               xyPositions[currentPlayer].x + (OFFSETTER1 * i),
+               (player[currentPlayer].cardLifted[i] ? (xyPositions[currentPlayer].y - OFFSETTER2 - 20) :(xyPositions[currentPlayer].y - OFFSETTER2)),
+               bitmap.width + (xyPositions[currentPlayer].x + OFFSETTER1 * i),
+               bitmap.height + (player[currentPlayer].cardLifted[i] ? (xyPositions[currentPlayer].y - OFFSETTER2 - 20) : (xyPositions[currentPlayer].y - OFFSETTER2)) 
+               }.IsPointInside(Point{x,y}) && drawButton[currentPlayer].disabled)
+
+            {
+               dragCard = player[currentPlayer].cardValues[i];
+               cardToReposition = i;
+               width = bitmap.width;
+               height = bitmap.height;
+               xCursorPositionAtCard = (xyPositions[currentPlayer].x + (OFFSETTER1 * i)) - x;
+               yCursorPositionAtCard = (player[currentPlayer].cardLifted[i] ? 
+                  (xyPositions[currentPlayer].y - OFFSETTER2 - y - 20) : 
+                  (xyPositions[currentPlayer].y - OFFSETTER2 - y));
+               flagButtonDown = true;
+               OnMouseMove(x,y,mods);
+               break;
+            }
+         }
+      }
+
+      return true;
+   }
+
+   bool OnRightButtonUp(int x, int y, Modifiers mods)
+   {
+      Bitmap bitmap = cardBack;
+      int swapCard,dest,source,i; 
+      Box boxPlayerCards={xyPositions[currentPlayer].x,xyPositions[currentPlayer].y - OFFSETTER2,
+         xyPositions[currentPlayer].x + player[currentPlayer].numCards * OFFSETTER1 + bitmap.width, 
+         xyPositions[currentPlayer].y - OFFSETTER2 + bitmap.height};
+      Box boxCard = {x + xCursorPositionAtCard,y + yCursorPositionAtCard, x + xCursorPositionAtCard,y + yCursorPositionAtCard + height - 1};
+
+      if(flagButtonDown)
+      {
+         if(boxCard.Overlap(boxPlayerCards))
+         {
+            swapCard = (x  + xCursorPositionAtCard >= player[currentPlayer].numCards * 15 + xyPositions[currentPlayer].x) ? 
+               (player[currentPlayer].numCards-1) : ((x  + xCursorPositionAtCard - xyPositions[currentPlayer].x) / 15);
+            if(cardToReposition > swapCard)
+            {
+               dest = swapCard + 1;
+               MoveBytes(&player[currentPlayer].cardValues[dest],
+                  &player[currentPlayer].cardValues[swapCard],(cardToReposition - swapCard) * sizeof(int));
+               player[currentPlayer].cardValues[swapCard] = dragCard;
+               //player[currentPlayer].cardLifted[swapCard] = false;
+            }
+            else
+            {
+               dest = cardToReposition;
+               source = cardToReposition + 1;
+               MoveBytes(&player[currentPlayer].cardValues[dest],
+                  &player[currentPlayer].cardValues[source],(swapCard - cardToReposition) * sizeof(int));
+                  player[currentPlayer].cardValues[swapCard] = dragCard;
+               //player[currentPlayer].cardLifted[swapCard] = false;   
+            }
+
+         }
+      
+         for(i=0;i<player[currentPlayer].numCards;i++)
+         {
+            player[currentPlayer].cardLifted[i] = false;
+         }   
+
+         flagButtonDown = false;
+         ReleaseCapture();
+         Update(null);
+      }
+      return true;
+   }
+}
+
+TongIts tongIts {};