home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 October / Chip Ekim 2003.iso / prog / share / tod / setup.exe / tetanus.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-16  |  36.2 KB  |  1,397 lines

  1. /* Notice
  2.  
  3. This program is free software; you can redistribute it and/or modify it under
  4. the terms of the GNU General Public License as published by the Free Software
  5. Foundation; either version 2 of the License, or (at your option) any later
  6. version.
  7.  
  8. This program is distributed in the hope that it will be useful and fun, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE.  See the License for more details.
  11.  
  12. You should have received a copy of the License along with this program,
  13. in the file COPYING; if not, write to the Free Software Foundation, Inc. /
  14. 59 Temple Place - Suite 330 / Boston, MA  02111-1307 / USA
  15. or view the License online at http://www.gnu.org/copyleft/gpl.html
  16.  
  17. The author can be reached by
  18.   usps:Damian Yerrick / Box 398 / 5500 Wabash Avenue / Terre Haute, IN 47803
  19.   mailto:dosarena@pineight.8m.com
  20.     http://come.to/yerrick
  21.  
  22. DOSArena is a trademark of Damian Yerrick. All other trademarks belong to
  23. their respective owners.
  24.  
  25. */
  26.  
  27. #include "tod.h"
  28.  
  29. //////////////////////////////////////////////////////////
  30. //////////////////////////////////////////////////////////
  31.  
  32. #define DIFFICULTY 350
  33. #define INITIAL_LEVEL 5 // is 10 in FPA tetanus but FPA has no drugz
  34.  
  35. /* This table defines the color for each type of block. */
  36. enum
  37. {
  38.   BCOL_J     = 0x10,
  39.   BCOL_S     = 0x20,
  40.   BCOL_STICK = 0x30,
  41.   BCOL_Z     = 0x40,
  42.   BCOL_L     = 0x50,
  43.   BCOL_T     = 0x60,
  44.   BCOL_O     = 0x70,
  45.   BCOL_H     = 0x90,
  46.   BCOL_R     = 0xa0,
  47.   BCOL_MULTISQUARE = 0xe0,
  48.   BCOL_MONOSQUARE = 0xf0,
  49.   BCOL_ALL   = 0xf0,
  50.  
  51.   /* utility tiles */
  52.   BCOL_LINECLEAR = 0x81,
  53.   BCOL_NEUTRAL = 0x80
  54. };
  55.  
  56.  
  57. /* This table defines connections.  For example, if BCON_E is set,
  58.    then this block is connected to the block on the E side and should
  59.    be shaded appropriately.  If BCON_E is clear, draw an edge.
  60. */
  61. enum
  62. {
  63.   BCON_NONE = 0,
  64.   BCON_E    = 1,
  65.   BCON_W    = 2,
  66.   BCON_WE   = BCON_W | BCON_E,
  67.   BCON_S    = 4,
  68.   BCON_SE   = BCON_S | BCON_E,
  69.   BCON_SW   = BCON_S | BCON_W,
  70.   BCON_SWE  = BCON_S | BCON_WE,
  71.   BCON_N    = 8,
  72.   BCON_NE   = BCON_N | BCON_E,
  73.   BCON_NW   = BCON_N | BCON_W,
  74.   BCON_NWE  = BCON_N | BCON_WE,
  75.   BCON_NS   = BCON_N | BCON_S,
  76.   BCON_NSE  = BCON_N | BCON_SE,
  77.   BCON_NSW  = BCON_N | BCON_SW,
  78.   BCON_NSWE = BCON_N | BCON_SWE,
  79.   BCON_ALL  = BCON_NSWE
  80. };
  81.  
  82. enum
  83. {
  84.   JPAD_BUTTON_UP = 0,
  85.   JPAD_BUTTON_DOWN = 1,
  86.   JPAD_BUTTON_LEFT = 2,
  87.   JPAD_BUTTON_RIGHT = 3,
  88.   JPAD_BUTTON_ROTL = 4,
  89.   JPAD_BUTTON_ROTR = 5,
  90.   JPAD_BUTTON_SWAP = 6,
  91.   JPAD_BUTTON_MISC = 7,
  92.  
  93.   JPAD_MASK_UP    = 0x80 >> JPAD_BUTTON_UP,
  94.   JPAD_MASK_DOWN  = 0x80 >> JPAD_BUTTON_DOWN,
  95.   JPAD_MASK_LEFT  = 0x80 >> JPAD_BUTTON_LEFT,
  96.   JPAD_MASK_RIGHT = 0x80 >> JPAD_BUTTON_RIGHT,
  97.   JPAD_MASK_ROTL  = 0x80 >> JPAD_BUTTON_ROTL,
  98.   JPAD_MASK_ROTR  = 0x80 >> JPAD_BUTTON_ROTR,
  99.   JPAD_MASK_SWAP  = 0x80 >> JPAD_BUTTON_SWAP,
  100.   JPAD_MASK_MISC  = 0x80 >> JPAD_BUTTON_MISC,
  101.  
  102. };
  103.  
  104. static const char gPieceColor[NUM_PIECES] =
  105. {
  106.   BCOL_T, BCOL_Z, BCOL_S, BCOL_J, BCOL_L,
  107.   BCOL_O, BCOL_Z, BCOL_STICK, BCOL_STICK, BCOL_STICK
  108. };
  109.  
  110. /* DATA TABLES
  111.  
  112.    This might need a little clarification. Take the T piece:
  113.      x={{0,1,2,1},{1,1,1,0},{2,1,0,1},{1,1,1,2}}
  114.      y={{1,1,1,2},{0,1,2,1},{1,1,1,0},{2,1,0,1}}
  115.    This is a set of (x, y) data for each block in each rotation
  116.    of the piece. The shape it defines is
  117.          0 1 2 3   0 1 2 3   0 1 2 3   0 1 2 3
  118.        0 . . . .   . X . .   . X . .   . X . .
  119.        1 X X X .   X X . .   X X X .   . X X .
  120.        2 . X . .   . X . .   . . . .   . X . .
  121.        3 . . . .   . . . .   . . . .   . . . .
  122.  
  123.    gCBlocks records which blocks exist and how they're connected
  124.    for display purposes.
  125.  */
  126. static const char gXBlocks[NUM_PIECES][NUM_FLIPS][NUM_BLOCKS] =
  127. {
  128.   {{0,1,2,1},{1,1,1,0},{2,1,0,1},{1,1,1,2}}, // t
  129.   {{0,1,1,2},{2,2,1,1},{2,1,1,0},{1,1,2,2}}, // z
  130.   {{0,1,1,2},{0,0,1,1},{2,1,1,0},{1,1,0,0}}, // s
  131.   {{0,1,2,2},{1,1,1,0},{2,1,0,0},{1,1,1,2}}, // j
  132.   {{0,0,1,2},{0,1,1,1},{2,2,1,0},{2,1,1,1}}, // l
  133.   {{1,1,2,2},{2,1,1,2},{2,2,1,1},{1,2,2,1}}, // package
  134.   {{1,1,2,2},{2,1,1,2},{2,2,1,1},{1,2,2,1}}, // 3-l
  135.   {{0,1,2,3},{1,1,1,1},{3,2,1,0},{1,1,1,1}}, // 4-stick
  136.   {{0,1,2,3},{1,1,1,1},{3,2,1,0},{1,1,1,1}}, // 2-stick
  137.   {{0,1,2,0},{1,1,1,0},{2,1,0,0},{1,1,1,0}}  // 3-stick
  138. };
  139.  
  140. static const char gYBlocks[NUM_PIECES][NUM_FLIPS][NUM_BLOCKS] =
  141. {
  142.   {{1,1,1,2},{0,1,2,1},{1,1,1,0},{2,1,0,1}},
  143.   {{1,1,2,2},{0,1,1,2},{2,2,1,1},{2,1,1,0}},
  144.   {{2,2,1,1},{0,1,1,2},{1,1,2,2},{2,1,1,0}},
  145.   {{1,1,1,2},{0,1,2,2},{1,1,1,0},{2,1,0,0}},
  146.   {{2,1,1,1},{0,0,1,2},{0,1,1,1},{2,2,1,0}},
  147.   {{1,2,2,1},{1,1,2,2},{2,1,1,2},{2,2,1,1}},
  148.   {{1,2,2,1},{1,1,2,2},{2,1,1,2},{2,2,1,1}},
  149.   {{2,2,2,2},{0,1,2,3},{2,2,2,2},{3,2,1,0}},
  150.   {{2,2,2,2},{0,1,2,3},{2,2,2,2},{3,2,1,0}},
  151.   {{2,2,2,0},{1,2,3,0},{2,2,2,0},{3,2,1,0}}
  152. };
  153.  
  154. /* big fat ass connection lut */
  155. static const char gCBlocks[NUM_PIECES][NUM_FLIPS][NUM_BLOCKS] =
  156. {
  157.   {
  158.     {BCON_E,BCON_SWE,BCON_W,BCON_N},
  159.     {BCON_S,BCON_NSW,BCON_N,BCON_E},
  160.     {BCON_W,BCON_NWE,BCON_E,BCON_S},
  161.     {BCON_N,BCON_NSE,BCON_S,BCON_W}
  162.   },
  163.   {
  164.     {BCON_E,BCON_SW,BCON_NE,BCON_W},
  165.     {BCON_S,BCON_NW,BCON_SE,BCON_N},
  166.     {BCON_W,BCON_NE,BCON_SW,BCON_E},
  167.     {BCON_N,BCON_SE,BCON_NW,BCON_S}
  168.   },
  169.   {
  170.     {BCON_E,BCON_NW,BCON_SE,BCON_W},
  171.     {BCON_S,BCON_NE,BCON_SW,BCON_N},
  172.     {BCON_W,BCON_SE,BCON_NW,BCON_E},
  173.     {BCON_N,BCON_SW,BCON_NE,BCON_S}
  174.   },
  175.   {
  176.     {BCON_E,BCON_WE,BCON_SW,BCON_N},
  177.     {BCON_S,BCON_NS,BCON_NW,BCON_E},
  178.     {BCON_W,BCON_WE,BCON_NE,BCON_S},
  179.     {BCON_N,BCON_NS,BCON_SE,BCON_W}
  180.   },
  181.   {
  182.     {BCON_N,BCON_SE,BCON_WE,BCON_W},
  183.     {BCON_E,BCON_SW,BCON_NS,BCON_N},
  184.     {BCON_S,BCON_NW,BCON_WE,BCON_E},
  185.     {BCON_W,BCON_NE,BCON_NS,BCON_S}
  186.   },
  187.   {
  188.     {BCON_SE,BCON_NE,BCON_NW,BCON_SW},
  189.     {BCON_SE,BCON_NE,BCON_NW,BCON_SW},
  190.     {BCON_SE,BCON_NE,BCON_NW,BCON_SW},
  191.     {BCON_SE,BCON_NE,BCON_NW,BCON_SW}
  192.   },
  193.   {
  194.     {BCON_SE,BCON_N,0,BCON_W},
  195.     {BCON_SW,BCON_E,0,BCON_N},
  196.     {BCON_NW,BCON_S,0,BCON_E},
  197.     {BCON_NE,BCON_W,0,BCON_S}
  198.   },
  199.   {
  200.     {BCON_E,BCON_WE,BCON_WE,BCON_W},
  201.     {BCON_S,BCON_NS,BCON_NS,BCON_N},
  202.     {BCON_W,BCON_WE,BCON_WE,BCON_E},
  203.     {BCON_N,BCON_NS,BCON_NS,BCON_S}
  204.   },
  205.   {
  206.     {0,BCON_E,BCON_W,0},
  207.     {0,BCON_S,BCON_N,0},
  208.     {0,BCON_W,BCON_E,0},
  209.     {0,BCON_N,BCON_S,0}
  210.   },
  211.   {
  212.     {BCON_E,BCON_WE,BCON_W,0},
  213.     {BCON_S,BCON_NS,BCON_N,0},
  214.     {BCON_W,BCON_WE,BCON_E,0},
  215.     {BCON_N,BCON_NS,BCON_S,0}
  216.   }
  217. };
  218.  
  219.  
  220.  
  221.  
  222. #define NUM_gTips 7
  223. /*
  224. static char gTips[NUM_gTips][2][32] =
  225. {
  226.   {"When reducing your stack, try", "taking advantage of gravity."},
  227.   {"Lines of all one color", "(H or R) count double."},
  228.   {"Try sliding one block", "under another block."},
  229.   {"Some days you win;", "some days it rains."},
  230.   {"Baking cookies with butter (not", "margarine) improves the flavor."},
  231.   {"To survive longer,", "lay sticks flat."},
  232.   {"The best defense is a good", "offense; make tetrises often."}
  233. };
  234. */
  235.  
  236. /* GLOBAL VARIABLES */
  237.  
  238. TetGlobals g = {NULL};
  239. Player p[2];
  240. static int attackMode = 0, raceMode = 0;
  241. int nPlayers = 1;
  242. static int curTurn = 0;
  243. #define ME p[curTurn] // to make accessing p[] easier
  244.  
  245. /* FUNCTION PROTOTYPES AND MACROS */
  246.  
  247. /* "Carbon" is the code name of the flood-fill based gravity algorithm. */
  248. static char CarbonStillGoing(void);
  249. static void DrawPiece(short x, short y, int inPiece, int inFlip, short color, short style);
  250. static void TeFloodFill(int x, int y, unsigned int c);
  251. static void FloodFillLoop(int x, int y, unsigned int c, unsigned int uc);
  252. static short MarkCarbon(int spinMove);
  253. static char CheckOverlap(short x, short y, short inPiece, short inFlip);
  254. static void PushUp(void);
  255. //static void ScrollDown(short top, short bottom);
  256. static void TeDrawBlock(int x, int y, unsigned colour);
  257. void TeShutDown(void);
  258. short TeStartUp(void);
  259. static void GetNewPiece(int depth);
  260.  
  261. int lastClock;
  262.  
  263.  
  264.  
  265. int ReadJPad(int n)
  266. {
  267.   static char polled[4] = {0, 0, 0, 0};
  268.   int i, out = 0;
  269.   int rightKeys[8] =
  270.   {
  271.     KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,
  272.     KEY_QUOTE, KEY_ENTER, KEY_OPENBRACE, KEY_CLOSEBRACE
  273.   };
  274.   int leftKeys[8] =
  275.   {
  276.     KEY_R, KEY_F, KEY_D, KEY_G, KEY_A, KEY_S, KEY_Q, KEY_W
  277.   };
  278.  
  279.   /* If in a 2P game without joysticks, read the left player
  280.    * from the left side of the keyboard.
  281.    */
  282.   if(nPlayers > 1 && (num_joysticks == 0 || g.usingJoy == 0))
  283.   {
  284.     if(n == 0)
  285.     {
  286.       for(i = 0; i < 8; i++)
  287.       {
  288.         out <<= 1;
  289.         if(key[leftKeys[i]])
  290.           out |= 1;
  291.       }
  292.       return out;
  293.     }
  294.     else
  295.       n--;
  296.   }
  297.  
  298.   if(n > num_joysticks)
  299.     return 0;
  300.  
  301.   /* If we have more players than joysticks, read the first player
  302.    * after the sticks from the right side of the keyboard.
  303.    */
  304.   if(n == num_joysticks || g.usingJoy == 0)
  305.   {
  306.     for(i = 0; i < 8; i++)
  307.     {
  308.       out <<= 1;
  309.       if(key[rightKeys[i]])
  310.         out |= 1;
  311.     }
  312.     return out;
  313.   }
  314.  
  315.   // If necessary, read the joysticks.
  316.   if(!polled[n])
  317.   {
  318.     poll_joystick();
  319.     for(i = 0; i < 4; i++)
  320.       polled[i] = 1;
  321.   }
  322.  
  323.   if(joy[n].stick[0].axis[1].d1) // up
  324.     out |= JPAD_MASK_UP;
  325.   if(joy[n].stick[0].axis[1].d2) // down
  326.     out |= JPAD_MASK_DOWN;
  327.   if(joy[n].stick[0].axis[0].d1) // left
  328.     out |= JPAD_MASK_LEFT;
  329.   if(joy[n].stick[0].axis[0].d2) // right
  330.     out |= JPAD_MASK_RIGHT;
  331.   if(joy[n].button[0].b)
  332.     out |= JPAD_MASK_ROTL;
  333.   if(joy[n].button[1].b)
  334.     out |= JPAD_MASK_ROTR;
  335.   if(joy[n].num_buttons > 2 && joy[n].button[2].b)
  336.     out |= JPAD_MASK_SWAP;
  337.   if(joy[n].num_buttons > 3 && joy[n].button[3].b)
  338.     out |= JPAD_MASK_MISC;
  339.  
  340.   /* Mark this joystick as "needs to be read next time." */
  341.   polled[n] = 0;
  342.   return out;
  343. }
  344.  
  345. /* MakeRepeats() ***********************
  346.  * Autorepeats digital pad motion.  After autoDelay/70 of a second, it repeats
  347.  * a key 70/autoRate times a second.
  348.  */
  349. void MakeRepeats(char *repeatTime, short j, short autoDelay, short autoRate)
  350. {
  351.   short i;
  352.  
  353.   for(i = 7; i >= 0; i--)
  354.   {
  355.     if(j & 0x01)
  356.     {
  357.       repeatTime[i]++;
  358.       if(repeatTime[i] >= autoDelay)
  359.         repeatTime[i] -= autoRate;
  360.     }
  361.     else
  362.     {
  363.       repeatTime[i] = 0;
  364.     }
  365.     j >>= 1;
  366.   }
  367. }
  368.  
  369.  
  370. /* CarbonStillGoing() ******************
  371.  * Moves everything down one line if still floating.
  372.  */
  373. static char CarbonStillGoing(void)
  374. {
  375.   static int lastTime = 0;
  376.   signed char flooded = 0;
  377.   short x, d, e, y;
  378.  
  379. /* debugging information: enable if you touched any function with Carbon in
  380.  * its name and your modifications make the program screw up */
  381.  
  382. /*
  383.   for(y = 0; y <= 20; y++)
  384.     for (x = 0; x < 10; x++)
  385.     {
  386.       gotoxy(x * 2 + 11, y + 1);
  387.       cputs("%d", (int)ME.auxMap.b[y][x]);
  388.     }
  389. */
  390.  
  391.   /* move everything down if it is floating */
  392.   for(x = 0; x < 10; x++)
  393.   {
  394.     e = ME.auxMap.b[20][x];
  395.     for(y = 20; y >= 0; y--)
  396.     {
  397.       d = e;
  398.       if(y > 0)
  399.         e = ME.auxMap.b[y - 1][x];
  400.       else
  401.     e = 0;
  402.       if((e != 1) && (d != 1))
  403.       {
  404.         ME.auxMap.b[y][x] = e;
  405.     if(y < 20)
  406.     {
  407.       if (y == 0)
  408.         ME.blockMap.b[y][x] = 0;
  409.       else
  410.         ME.blockMap.b[y][x] = ME.blockMap.b[y - 1][x];
  411.           TeDrawBlock(x, y,
  412.                       ME.blockMap.b[y][x] ? ME.blockMap.b[y][x] : 0);
  413.     }
  414.       }
  415.     }
  416.   }
  417.  
  418.   /* if something just hit the ground, mark it as ground */
  419.   for(y = 19; y >= 0; y--)
  420.     for(x = 0; x <= 9; x++)
  421.       if((ME.auxMap.b[y][x] > 1) && (ME.auxMap.b[y + 1][x] == 1))
  422.       {
  423.     TeFloodFill(x, y, 1);
  424.     flooded = 1;
  425.       }
  426.  
  427.   /* if something hit the ground, play a thud */
  428.   if(flooded)
  429.     /*SendSound(gDropSound)*/;
  430.  
  431.   ME.y++; /* for scrolling the clear into visibility */
  432.  
  433.   /* if everything isn't ground, we're still going */
  434.   for(y = 0; y <= 19; y++)
  435.     for(x = 0; x < 20; x++)
  436.       if(ME.auxMap.b[y][x] > 1)
  437.     return 1;
  438.  
  439.   /* FIXME: these lines spinwait! */
  440.   while(lastTime == retrace_count);
  441.   lastTime = retrace_count;  
  442.  
  443.   return 0;
  444. }
  445.  
  446.  
  447. static void BreakLineLoop(int x, int y)
  448. {
  449.   int c = ME.blockMap.b[y][x];
  450.  
  451.   if((c & BCOL_ALL) >= BCOL_MULTISQUARE)
  452.   {
  453.     if(y < 19 && ME.blockMap.b[y + 1][x] != 0)
  454.     {
  455.       ME.blockMap.b[y + 1][x] &= ~BCON_N;
  456.       TeDrawBlock(x, y + 1, ME.blockMap.b[y + 1][x]);
  457.     }
  458.     if(y > 0 && ME.blockMap.b[y - 1][x] != 0)
  459.     {
  460.       ME.blockMap.b[y - 1][x] &= ~BCON_S;
  461.       TeDrawBlock(x, y - 1, ME.blockMap.b[y - 1][x]);
  462.     }
  463.     return;
  464.   }
  465.  
  466.   if(g.tntMode)
  467.     ME.blockMap.b[y][x] = BCOL_NEUTRAL;
  468.   else
  469.     ME.blockMap.b[y][x] &= ~BCON_ALL;
  470.   TeDrawBlock(x, y, ME.blockMap.b[y][x]);
  471.   if((c & BCON_N) && y > 0)
  472.     BreakLineLoop(x, y - 1);
  473.   if((c & BCON_S) && y < 19)
  474.     BreakLineLoop(x, y + 1);
  475.   if((c & BCON_W) && y > 0)
  476.     BreakLineLoop(x - 1, y);
  477.   if((c & BCON_E) && x < 9)
  478.     BreakLineLoop(x + 1, y);
  479. }
  480.  
  481.  
  482. #define USE_TENGEN_BREAKLINE 0
  483.  
  484.  
  485. /* BreakLine() *************************
  486.  * Break connections between blocks on this row and blocks on
  487.  * neighboring rows.
  488.  */
  489. static void BreakLine(int y)
  490. {
  491.   int x;
  492.  
  493. /* BreakLine() *************************
  494.  * Break connections inside blocks on this row.
  495.  */
  496.  
  497. #if USE_TENGEN_BREAKLINE
  498.   if(y > 0)
  499.     for(x = 0; x < 10; x++)
  500.       if(ME.blockMap.b[y - 1][x] & BCON_S)
  501.       {
  502.         ME.blockMap.b[y - 1][x] &= ~BCON_S;
  503.         TeDrawBlock(x, y - 1, ME.blockMap.b[y - 1][x]);
  504.       }
  505.  
  506.   if(y < 19)
  507.     for(x = 0; x < 10; x++)
  508.       if(ME.blockMap.b[y + 1][x] & BCON_N)
  509.       {
  510.         ME.blockMap.b[y + 1][x] &= ~BCON_N;
  511.         TeDrawBlock(x, y + 1, ME.blockMap.b[y + 1][x]);
  512.       }
  513. #else
  514.   for(x = 0; x < 10; x++)
  515.   {
  516.     if((ME.blockMap.b[y][x] & BCON_ALL) != 0)
  517.       BreakLineLoop(x, y);
  518.   }
  519. #endif
  520.  
  521. }
  522.  
  523.  
  524. /* MarkSquaresTest() *******************
  525.  * Look for a TNT square in this position.  Return 1 if found.
  526.  * Assumes: 0 <= x <= 6; 0 <= y <= 16
  527.  */
  528. static int MarkSquaresTest(int x, int y, int multiOK)
  529. {
  530.   int i, j, firstColor = ME.blockMap.b[y][x] & BCOL_ALL;
  531.  
  532.   for(i = 0; i <= 3; i++)
  533.   {
  534.     /* don't allow squares within parts of squares */
  535.     if((ME.blockMap.b[y + i][x] & BCOL_ALL) >= BCOL_MULTISQUARE)
  536.       return 0;
  537.     /* the block doesn't connect on the left */
  538.     if(ME.blockMap.b[y + i][x] & BCON_W)
  539.       return 0;
  540.     /* the block doesn't connect on the right */
  541.     if(ME.blockMap.b[y + i][x + 3] & BCON_E)
  542.       return 0;
  543.     /* the block doesn't connect on the top */
  544.     if(ME.blockMap.b[y][x + i] & BCON_N)
  545.       return 0;
  546.     /* the block doesn't connect on the bottom */
  547.     if(ME.blockMap.b[y + 3][x + i] & BCON_S)
  548.       return 0;
  549.  
  550.     for(j = 0; j <= 3; j++)
  551.     {
  552.       int c = ME.blockMap.b[y + i][x + j];
  553.  
  554.       /* the square contains no single blocks */
  555.       if((c & BCON_ALL) == 0)
  556.         return 0;
  557.       /* if looking for monosquares, disallow multisquares */
  558.       if(multiOK == 0 && (c & BCOL_ALL) != firstColor)
  559.         return 0;
  560.     }
  561.   }
  562.   return 1;
  563. }
  564.  
  565. /* MarkSquare() ************************
  566.  * Places a multisquare or monosquare in the field.
  567.  */
  568. static void MarkSquare(int x, int y, int multiOK)
  569. {
  570.   int i, j, c;
  571.  
  572.   multiOK = (multiOK ? BCOL_MULTISQUARE : BCOL_MONOSQUARE) | BCON_ALL;
  573.   for(i = 0; i <= 3; i++)
  574.   {
  575.     if(i == 0)
  576.       c = multiOK & ~BCON_N;
  577.     else if(i == 3)
  578.       c = multiOK & ~BCON_S;
  579.     else
  580.       c = multiOK;
  581.  
  582.     for(j = 0; j <= 3; j++)
  583.     {
  584.       if(j == 0)
  585.         ME.blockMap.b[y + i][x + j] = c & ~BCON_W;
  586.       else if(j == 3)
  587.         ME.blockMap.b[y + i][x + j] = c & ~BCON_E;
  588.       else
  589.         ME.blockMap.b[y + i][x + j] = c;
  590.       TeDrawBlock(x + j, y + i, ME.blockMap.b[y + i][x + j]);
  591.     }
  592.   }
  593.  
  594. }
  595.  
  596.  
  597. /* MarkSquares() ***********************
  598.  * Create TNT monosquares and multisquares.
  599.  */
  600. static void MarkSquares(int multiOK)
  601. {
  602.   int x, y;
  603.  
  604.   for(y = 16; y >= 0; y--)
  605.     for(x = 0; x <= 6; x++)
  606.       if(ME.blockMap.b[y][x] & BCON_ALL)
  607.         if(MarkSquaresTest(x, y, multiOK))
  608.           MarkSquare(x, y, multiOK);
  609. }
  610.  
  611.  
  612. /* CheckLines() *****************
  613.  * Clears horizontal rows using Carbon (flood fill drops) algorithm.
  614.  */
  615. static char CheckLines(int spinMove)
  616. {
  617.   int wiener = 0, chainCount = 0;
  618.   int x, y;
  619.   static int fib[20] =
  620.     {1, 1, 1, 2, 3, 5, 8, 13, 21, 34,
  621.      55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181};
  622.  
  623.   if(g.tntMode)
  624.   {
  625.     MarkSquares(0);
  626.     MarkSquares(1);
  627.   }
  628.  
  629.   ME.y = 19;
  630.  
  631.   for(y = 0; y <= 19; y++)
  632.   {
  633.     int hCount = 0, rCount = 0, grayCount = 0;
  634.     for(x = 0; x < 10; x++)
  635.     {
  636.       switch(ME.blockMap.b[y][x] & BCOL_ALL)
  637.       {
  638.         case 0:
  639.           break;
  640.         case BCOL_H:
  641.           hCount++;
  642.           break;
  643.         case BCOL_R:
  644.           rCount++;
  645.           break;
  646.         default:
  647.           grayCount++;
  648.           break;
  649.       }
  650.     }
  651.     if(hCount + rCount + grayCount == 10)
  652.     {
  653.       /* break lines up and down */
  654.       BreakLine(y);
  655.  
  656.       /* remove the line */
  657.       for(x = 0; x < 10; x++)
  658.       {
  659.         switch(ME.blockMap.b[y][x] & (BCON_WE | BCOL_ALL))
  660.         {
  661.           case BCOL_MONOSQUARE | BCON_E:
  662.             ME.score += 1000;
  663.             break;
  664.           case BCOL_MULTISQUARE | BCON_E:
  665.             ME.score += 500;
  666.             break;
  667.           default:
  668.             break;
  669.         }
  670.  
  671.         ME.blockMap.b[y][x] = 0;
  672.         TeDrawBlock(x, y, BCOL_LINECLEAR);
  673.       }
  674.  
  675.       /* score the line */
  676.       if(ME.scoreFac && attackMode)
  677.         p[1 - curTurn].coming++;
  678.       if(g.tntMode)
  679.         ME.score += fib[(int)(ME.scoreFac++)] * 100;
  680.       else
  681.         ME.score += (int)(++ME.scoreFac) * 100;
  682.       ME.lines++;
  683.       wiener++;
  684.  
  685.       /* if H or R line, score double */
  686.       if(hCount == 10 || rCount == 10)
  687.       {
  688.         ME.scoreFac++;
  689.         ME.score += (int)(ME.scoreFac) * 100;
  690.     ME.lines++;
  691.         wiener++;
  692.       }
  693.       /* scroll the action on screen */
  694.       if(y < ME.y)
  695.         ME.y = y;
  696.     }
  697.   }
  698.   if(wiener)
  699.   {
  700.     // Handle the combo counter.
  701. //    textprintf(screen, font, chainCount * 12, 0, 12, "%d", wiener);
  702.     chainCount++;
  703. //    SendSound(gLineSound);
  704.  
  705.     if(spinMove)
  706.     {
  707.       /* break apart all the pieces */
  708.  
  709.       if(g.tntMode)
  710.       {
  711.         for(y = 0; y < 20; y++)
  712.           for(x = 0; x < 10; x++)
  713.             if(ME.blockMap.b[y][x])
  714.               ME.blockMap.b[y][x] = BCOL_NEUTRAL;
  715.       }
  716.       else
  717.       {
  718.         for(y = 0; y < 20; y++)
  719.           for(x = 0; x < 10; x++)
  720.             ME.blockMap.b[y][x] &= ~BCOL_ALL;
  721.       }
  722.     }
  723.  
  724.     MarkCarbon(spinMove);
  725.   }
  726.   return wiener;
  727. }
  728.  
  729. /* DrawPiece() ************************
  730.  * This probably won't need to be changed too much when someone
  731.  * ports Tetanus to other platforms.  What you'll need to change
  732.  * is TeDrawBlock.
  733.  */
  734. static void DrawPiece(short x, short y,
  735.                int inPiece, int inFlip, short color, short style)
  736. {
  737.   int n, k;
  738.  
  739.   switch(style)
  740.   {
  741.     case 0: /* erase */
  742.       for(n = 0; n < NUM_BLOCKS; n++)
  743.         if(gCBlocks[inPiece][inFlip][n])
  744.       TeDrawBlock(x + gXBlocks[inPiece][inFlip][n],
  745.                       y + gYBlocks[inPiece][inFlip][n],
  746.                       0);
  747.       break;
  748.     case 1: /* high intensity */
  749.       for(n = 0; n < NUM_BLOCKS; n++)
  750.         if(gCBlocks[inPiece][inFlip][n])
  751.       TeDrawBlock(x + gXBlocks[inPiece][inFlip][n],
  752.                       y + gYBlocks[inPiece][inFlip][n],
  753.                       color);
  754.       break;
  755.     case 2: /* low intensity and copy to ME.blockMap.b */
  756.       for(n = 0; n < NUM_BLOCKS; n++)
  757.       {
  758.         int blkType = gCBlocks[inPiece][inFlip][n];
  759.         if(blkType != 0)
  760.     {
  761.           int j = y + gYBlocks[inPiece][inFlip][n];
  762.  
  763.       if (ME.top > j) ME.top = j;
  764.       if (j >= 0)
  765.       {
  766.             k = x + gXBlocks[inPiece][inFlip][n];
  767.             ME.blockMap.b[j][k] = color | blkType;
  768.             TeDrawBlock(k, j, color | blkType);
  769.       }
  770.     }
  771.       }
  772.       break;
  773.   }
  774. }
  775.  
  776.  
  777. /* DrawNext() **************************
  778.  * THIS MUST BE PORTED UP THE ASS for each new tetanus platform.
  779.  */
  780. void DrawNext(int pl)
  781. {
  782.   unsigned i, n;
  783.  
  784.   int xcellsize = SCREEN_W / 40;
  785.   int ycellsize = SCREEN_H / 30;
  786.  
  787.   for(i = 1; i <= 4; i++)
  788.   {
  789.     unsigned colour = p[pl].curColor[i];
  790.     unsigned inPiece = p[pl].curPiece[i];
  791.     int xSrc = (colour & BCON_ALL) << 3;
  792.     int ySrc = (colour & BCOL_ALL) >> 1;
  793.     int yBase = (i == 4) ? 1 : 5 + i * 3;
  794.  
  795.     for(n = 0; n < NUM_BLOCKS; n++)
  796.     {
  797.       if(gCBlocks[inPiece][0][n])
  798.       {
  799.         int xDst = gXBlocks[inPiece][0][n];
  800.         int yDst = gYBlocks[inPiece][0][n] + yBase;
  801.  
  802.         stretch_blit(tetbits, p[pl].seven->frontBuf,
  803.                      xSrc, ySrc, 8, 8,
  804.                      xDst * xcellsize + p[pl].seven->nextX,
  805.                      yDst * ycellsize,
  806.                      xcellsize, ycellsize);
  807.       }
  808.     }
  809.   }
  810. }
  811.  
  812.  
  813. /* TeFloodFill() ************************
  814.  * This pair of functions fills an area with color.  They have been
  815.  * adapted to the context of Tetanus by marking any contiguous block
  816.  * area with a given unique falling block.
  817.  */
  818. static void TeFloodFill(int x, int y, unsigned int c)
  819. {
  820.   FloodFillLoop(x, y, c, ME.auxMap.b[y][x]);
  821.   ME.auxMap.b[y][x] = c;
  822. }
  823.  
  824. static void FloodFillLoop(int x, int y, unsigned int c, unsigned int fillC)
  825. {
  826.   int fillL, fillR, i;
  827.   int wiener = 1;
  828.  
  829.   fillL = fillR = x;
  830.   while(wiener)
  831.   {
  832.     ME.auxMap.b[y][fillL] = c;
  833.     fillL--;
  834.     wiener = (fillL < 0) ? 0 : (ME.auxMap.b[y][fillL] == fillC);
  835.   }
  836.   fillL++;
  837.  
  838.   wiener = 1;
  839.   while(wiener)
  840.   {
  841.     ME.auxMap.b[y][fillR] = c;
  842.     fillR++;
  843.     wiener = (fillR > 9) ? 0 : (ME.auxMap.b[y][fillR] == fillC);
  844.   }
  845.   fillR--;
  846.  
  847.   for(i = fillL; i <= fillR; i++)
  848.   {
  849.     if(y > 0)
  850.       if(ME.auxMap.b[y - 1][i] == fillC)
  851.     FloodFillLoop(i, y - 1, c, fillC);
  852.     if(y < 20)
  853.       if(ME.auxMap.b[y + 1][i] == fillC)
  854.     FloodFillLoop(i, y + 1, c, fillC);
  855.   }
  856. }
  857.  
  858. static void GameOver(int pl)
  859. {
  860.   p[pl].state = STATE_GAMEOVER;
  861.  
  862.   /* UINT_MAX minutes carries us past Y10K */
  863.   p[pl].high.when = p[pl].gameStarted / 60;
  864.   p[pl].high.duration = time(0) - p[pl].gameStarted;
  865.   p[pl].high.score[0] = p[pl].score;
  866.   p[pl].high.score[1] = p[pl].lines;
  867. }
  868.  
  869.  
  870. /* GameLoop() *************************
  871.  * Play one frame of the game.  Return 0 for continue or 1 for gameover.
  872.  */
  873. int GameLoop(void)
  874. {
  875.   int i, j;
  876.   signed char lastEnter[2] = {1, 1};
  877.   signed char won = 0;
  878.  
  879. //  signed char buf[256];
  880.  
  881. //  yield_timeslice();
  882.   
  883.   for(curTurn = 0; curTurn < nPlayers; curTurn++)
  884.   {
  885.     switch(ME.state)
  886.     {
  887.       case STATE_INACTIVE:
  888.         /* restart key is both flips */
  889.         j = ReadJPad(curTurn);
  890.         i = ((j & (JPAD_MASK_ROTL | JPAD_MASK_ROTR)) ==
  891.              (JPAD_MASK_ROTL | JPAD_MASK_ROTR));
  892.         ME.coming = 0;
  893.         if(i && !lastEnter[curTurn] && !won)
  894.           NewGame(curTurn);
  895.         lastEnter[curTurn] = i;
  896.         yield_timeslice();
  897.         break;
  898.  
  899.       case STATE_GET_NEW_PIECE:
  900.         for(i = 0; i < 3; i++)
  901.         {
  902.           ME.curPiece[i] = ME.curPiece[i + 1];
  903.           ME.curColor[i] = ME.curColor[i + 1];
  904.         }
  905.         GetNewPiece(3);
  906.  
  907.         /* Draw the next pieces. Not applicate */
  908.     /*
  909.         DrawPiece(0, 0, ME.curPiece[1], 0, ME.curColor[1], 3);
  910.     */
  911.  
  912.         ME.x = 3;
  913.         ME.y = -3;
  914.         ME.vis = 1;
  915.         ME.state = STATE_FALLING_PIECE;
  916.         ME.stateTime = retrace_count + 16;
  917.         ME.hasSwitched = ME.curFlip = ME.pieceDone = 0;
  918.         DrawPiece(ME.x, ME.y, ME.curPiece[0], 0, ME.curColor[0], 1);
  919.         break;
  920.  
  921.       case STATE_FALLING_PIECE:
  922.       /* read the keyboard and joystick */
  923.         j = ReadJPad(curTurn);
  924.  
  925.         MakeRepeats(ME.repeatTime, j, 18, 2);
  926.  
  927.         if(ME.repeatTime[6] == 1 ||
  928.            (ME.repeatTime[4] == 1 && ME.repeatTime[5] > 0) ||
  929.            (ME.repeatTime[5] == 1 && ME.repeatTime[4] > 0)) /* swap button */
  930.         {
  931.           if(!ME.hasSwitched)
  932.           {
  933.             DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 0);
  934.  
  935.             j = ME.curPiece[0];
  936.             ME.curPiece[0] = ME.curPiece[4];
  937.             ME.curPiece[4] = j;
  938.             j = ME.curColor[0];
  939.             ME.curColor[0] = ME.curColor[4];
  940.             ME.curColor[4] = j;
  941.  
  942.             ME.x = 3;
  943.             ME.y = -3;
  944.             ME.vis = 1;
  945.             ME.stateTime = retrace_count + 16;
  946.             ME.hasSwitched = 1;
  947.             ME.curFlip = ME.pieceDone = 0;
  948.             DrawPiece(ME.x, ME.y, ME.curPiece[0], 0, ME.curColor[0], 1);
  949.             ME.repeatTime[4] = ME.repeatTime[5] = 2; /* wait for release */
  950.             break; /* change state */
  951.           }
  952.         }
  953.  
  954.         /* rotate left.  Rotating squares is pointless so don't even try. */
  955.         if(ME.repeatTime[4 + ME.inverse] == 1 && ME.curPiece[0] != PIECE_SQUARE)
  956.         {
  957.           if(!CheckOverlap(ME.x, ME.y, ME.curPiece[0], (ME.curFlip + 3) & 3))
  958.           {
  959. //            SendSound(gFlipSound);
  960.             if(ME.vis)
  961.               DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 0);
  962.             ME.curFlip = (ME.curFlip + 3) & 3;
  963.             ME.vis = 0;
  964.             ME.dropMove = 0;
  965.           }
  966.         }
  967.  
  968.         // flip right
  969.         if(ME.repeatTime[5 - ME.inverse] == 1 && ME.curPiece[0] != PIECE_SQUARE)
  970.         {
  971.           if(!CheckOverlap(ME.x, ME.y, ME.curPiece[0], (ME.curFlip + 1) & 3))
  972.         {
  973. //            SendSound(gFlipSound);
  974.         if(ME.vis)
  975.               DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 0);
  976.         ME.curFlip = (ME.curFlip + 1) & 3;
  977.         ME.vis = 0;
  978.             ME.dropMove = 0;
  979.           }
  980.         }
  981.  
  982.         if(ME.repeatTime[2 + ME.inverse] == 1 ||
  983.            ME.repeatTime[2 + ME.inverse] == 17) // move left
  984.         {
  985.           if(!CheckOverlap(ME.x - 1, ME.y, ME.curPiece[0], ME.curFlip))
  986.           {
  987. //            Note(1, 81, 112, 0, 1);
  988.             if(ME.vis)
  989.               DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 0);
  990.             ME.x--;
  991.             ME.vis = 0;
  992.             ME.dropMove = 0;
  993.           }
  994.           else
  995.             ME.repeatTime[2] = 16; // let player slide the block in
  996.         }
  997.  
  998.         if(ME.repeatTime[1]) // move down
  999.         {
  1000.           if(ME.stateTime - retrace_count > 1)
  1001.           {
  1002.             ME.stateTime = retrace_count + 1;
  1003.             if(!g.tntMode)
  1004.               ME.score++;
  1005.             ME.dropMove = 0;
  1006.           }
  1007.         }
  1008.  
  1009.         if(ME.repeatTime[3 - ME.inverse] == 1 ||
  1010.            ME.repeatTime[3 - ME.inverse] == 17) // move right
  1011.         {
  1012.           if(!CheckOverlap(ME.x + 1, ME.y, ME.curPiece[0], ME.curFlip))
  1013.           {
  1014. //            Note(1, 81, 112, 0, 1);
  1015.           if(ME.vis)
  1016.               DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 0);
  1017.         ME.x++;
  1018.         ME.vis = 0;
  1019.           }
  1020. /*
  1021.           else if(gCheatCodes[2].flag && ME.repeatTime[1] != 0)
  1022.           {
  1023.             ME.stateTime = retrace_count;
  1024.           }
  1025. */
  1026.           else
  1027.             ME.repeatTime[3] = 16; // let player slide the block in
  1028.         }
  1029.  
  1030.         if(ME.repeatTime[0] == 1 && ME.dropMove == 0) // drop
  1031.         {
  1032.           ME.vis = 0;
  1033.           ME.stateTime = retrace_count;
  1034.           DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 0);
  1035.           do
  1036.           {
  1037.             ME.y++;
  1038.             if(!g.tntMode)
  1039.               ME.score++;
  1040.           } while(!CheckOverlap(ME.x, ME.y, ME.curPiece[0], ME.curFlip));
  1041.           ME.y--;
  1042.           if(!g.tntMode)
  1043.             ME.score--;
  1044.           ME.dropMove = 1;
  1045.         }
  1046.  
  1047.         // is it time to move the piece down 1?
  1048.         if(ME.stateTime - retrace_count <= 0)
  1049.         {
  1050.           if(CheckOverlap(ME.x, ME.y + 1, ME.curPiece[0], ME.curFlip) != 0)
  1051.           {
  1052.             /* give the player some time to slide the piece in before
  1053.              * it locks into place
  1054.              */
  1055.             if(ME.stateTime - retrace_count <= -30)
  1056.             {
  1057.               if(ME.pieceDone == 0)
  1058.                 ME.pieceDone = 1;
  1059. //              SendSound(gDropSound);
  1060.  
  1061.               /* check for a spinmove */
  1062.               ME.spinMove =
  1063.                 CheckOverlap(ME.x + 1, ME.y, ME.curPiece[0], ME.curFlip) &&
  1064.                 CheckOverlap(ME.x - 1, ME.y, ME.curPiece[0], ME.curFlip) &&
  1065.                 CheckOverlap(ME.x, ME.y - 1, ME.curPiece[0], ME.curFlip);
  1066.               DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 2);
  1067.               ME.scoreFac = 0;
  1068.               ME.chainCount = 0;
  1069.               ME.state = STATE_CHECK4LINES;
  1070.             }
  1071.           }
  1072.           else
  1073.           {
  1074.             if(ME.vis)
  1075.               DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 0);
  1076.             ME.vis--;
  1077.         ME.y++;
  1078.             if(raceMode)
  1079.               ME.stateTime = retrace_count + DIFFICULTY /
  1080.                              (ME.lines + ME.handiLines + INITIAL_LEVEL);
  1081.             else
  1082.               ME.stateTime = retrace_count + 2 * DIFFICULTY /
  1083.                              (ME.lines + ME.handiLines + 2 * INITIAL_LEVEL);
  1084.             ME.dropMove = 0;
  1085.           }
  1086.         }
  1087.  
  1088.         if(ME.vis != 1)
  1089.         {
  1090.           DrawPiece(ME.x, ME.y, ME.curPiece[0], ME.curFlip, ME.curColor[0], 1);
  1091.       ME.vis = 1;
  1092.         }
  1093.         break;
  1094.  
  1095.       case STATE_CHECK4LINES:
  1096.         /* check for lines */
  1097.         if(CheckLines(ME.spinMove))
  1098.         {
  1099.           ME.state = STATE_FALL;
  1100.           ME.stateTime = retrace_count + 20;
  1101.         }
  1102.         else
  1103.           ME.state = STATE_PUSHUP;
  1104.         ME.dropMove = 0;
  1105.         break;
  1106.  
  1107.       case STATE_FALL:
  1108.         if(retrace_count - ME.stateTime >= 0)
  1109.         {
  1110.           ME.stateTime += 3;
  1111.           if(!CarbonStillGoing())
  1112.             ME.state = STATE_CHECK4LINES;
  1113.         }
  1114.         break;
  1115.  
  1116.       case STATE_PUSHUP:
  1117.         if(retrace_count - ME.stateTime >= 0)
  1118.         {
  1119.           ME.stateTime += 3;
  1120.  
  1121.           if(p[1].coming > p[0].coming)
  1122.           {
  1123.             p[1].coming -= p[0].coming;
  1124.             p[0].coming = 0;
  1125.           }
  1126.           else
  1127.           {
  1128.             p[0].coming -= p[1].coming;
  1129.             p[1].coming = 0;
  1130.           }
  1131.  
  1132.           if(ME.coming > 0)
  1133.           {
  1134.             PushUp();
  1135.             ME.coming--;
  1136.           }
  1137.           else
  1138.           {
  1139.             if(MarkCarbon(0))
  1140.               ME.state = STATE_FALL;
  1141.             else if(ME.pieceDone == 0)
  1142.               ME.state = STATE_FALLING_PIECE;
  1143.             else if(ME.top >= 0)
  1144.             {
  1145.               // remove inverse
  1146.               if(ME.scoreFac >= 1)
  1147.               {
  1148.                 ME.inverse = 0;
  1149.  
  1150.                 // play tetris sound and add an item
  1151.                 if(ME.scoreFac >= 4)
  1152.                 {
  1153. //                  SendSound(gTetrisSound);
  1154.                   // If player has nothing in the item box, add an item, but
  1155.                   // don't add an inverse in non-versus mode.
  1156.                   if(ME.curPiece[4] < 0)
  1157.                     ME.curPiece[4] = PIECE_MAGNET + rand() % (attackMode + 1);
  1158.                 }
  1159.               }
  1160.               ME.state = STATE_GET_NEW_PIECE;
  1161.             }
  1162.             else
  1163.             {
  1164.               if(attackMode)
  1165.                 p[1 - curTurn].wins++;
  1166.               GameOver(curTurn);
  1167.               return 1;
  1168.             }
  1169.           }
  1170.         }
  1171.         break;
  1172.       case STATE_GAMEOVER:
  1173.         return 1;
  1174.     }
  1175.   }
  1176.   return 0;
  1177. }
  1178.  
  1179. /* GetNewPiece() ***********************
  1180.  * Places a new random piece in the piece queue.
  1181.  */
  1182. static void GetNewPiece(int depth)
  1183. {
  1184.   if(g.tntMode)
  1185.   { /* tnt way (DEBUG ONLY) */
  1186.     int piece = ME.curPiece[depth] = rand() % 7;
  1187.     ME.curPiece[depth] = (piece == 6) ? 7 : piece;
  1188.     ME.curColor[depth] = gPieceColor[ME.curPiece[depth]];
  1189.   }
  1190.   else
  1191.   { /* tetanus way */
  1192.     ME.curPiece[depth] = rand() % (g.teflonMode ? NUM_PIECES - 3 : NUM_PIECES);
  1193.     ME.curColor[depth] = ((rand() >> 9) & 0x10) + BCOL_H;
  1194.   }
  1195. }
  1196.  
  1197.  
  1198. /* MarkCarbon() ************************
  1199.  * This function marks areas of blocks as either ground or floating by filling
  1200.  * contiguous areas with a value denoting to which area each block belongs.
  1201.  */
  1202. static short MarkCarbon(int spinMove)
  1203. {
  1204.   int markX, markY;
  1205.   unsigned char q = 0;
  1206.  
  1207.   if(spinMove)
  1208.     /*SendSound(gTetrisSound)*/;
  1209.  
  1210.   for(markY = 0; markY < 20; markY++)
  1211.     for(markX = 0; markX < 10; markX++)
  1212.       ME.auxMap.b[markY][markX] = -(ME.blockMap.b[markY][markX] != 0);
  1213.   for(markX = 0; markX < 10; markX++)
  1214.     ME.auxMap.b[20][markX] = 255;
  1215.  
  1216.   for(markY = 20; markY >= 0; markY--)
  1217.     for(markX = 0; markX < 10; markX++)
  1218.       if(ME.auxMap.b[markY][markX] == 255)
  1219.       {
  1220.         if(spinMove)
  1221.         {
  1222.           if(markY == 20) // the bottom row should be all 1's
  1223.           {
  1224.             q = 1;
  1225.             ME.auxMap.b[markY][markX] = q;
  1226.           }
  1227.           else if(ME.auxMap.b[markY + 1][markX]) // booth's algorithm?
  1228.             ME.auxMap.b[markY][markX] = ME.auxMap.b[markY + 1][markX];
  1229.           else
  1230.             ME.auxMap.b[markY][markX] = ++q;
  1231.         }
  1232.         else
  1233.           TeFloodFill(markX, markY, ++q);
  1234.       }
  1235.   return (q > 1);
  1236. }
  1237.  
  1238. /* NewGame() ***************************
  1239.  * Sets up the grid and other parameters for a game of Tetanus.
  1240.  */
  1241. void NewGame(int pl)
  1242. {
  1243.   int x, y;
  1244.   int oldTurn = curTurn;
  1245.  
  1246.   curTurn = pl;
  1247. /*
  1248.   alert("NewGame() called. displaying", "backbuf, backbits, tetbits", "",
  1249.         "ok", 0, 13, 0);
  1250.  
  1251.   blit(ME.seven->backBuf, ME.seven->backBuf, xDest, yDest, xDest, yDest, 8, 8);
  1252.   readkey();
  1253.   blit(g.backbits, ME.seven->backBuf, xDest, yDest, xDest, yDest, 8, 8);
  1254.   readkey();
  1255.   blit(tetbits, ME.seven->backBuf, xSrc, ySrc, xDest, yDest, 8, 8);
  1256.   readkey();
  1257. */
  1258.   /* set up initial next pieces */
  1259.   for(y = 1; y <= 4; y++)
  1260.   {
  1261.     GetNewPiece(y);
  1262.   }
  1263.  
  1264.   /* clear field */
  1265.   for(y = 0; y < 20; y++)
  1266.   {
  1267.     for(x = 0; x < 10; x++)
  1268.     {
  1269.       p[pl].blockMap.b[y][x] = p[pl].auxMap.b[y][x] = 0;
  1270.       TeDrawBlock(x, y, 0);
  1271.     }
  1272.   }
  1273.  
  1274.   /* init variables */
  1275.   p[pl].score = p[pl].lines = p[pl].coming = p[pl].inverse = 0;
  1276.   ME.top = 20;
  1277.   ME.state = STATE_GET_NEW_PIECE;
  1278.   srand(ME.gameStart = retrace_count);
  1279.   ME.repeatTime[6] = 5;
  1280.  
  1281.   p[pl].gameStarted = time(0);
  1282.  
  1283.   /* add lines for handicap */
  1284.   y = g.handicap;
  1285.   if(curTurn == 1)  /* negative handicaps hurt player 2 */
  1286.     y = -y;
  1287.   if(y > 0)
  1288.     ME.handiLines = y * 10;
  1289.   else
  1290.     ME.handiLines = 0;
  1291.   while(y-- > 0)
  1292.     PushUp();
  1293.  
  1294.   /* hack to make sure autorepeat doesn't fuck us */
  1295.   for(y = 0; y < 8; y++)
  1296.     ME.repeatTime[y] = 1;
  1297.  
  1298.   curTurn = oldTurn;
  1299. }
  1300.  
  1301. /* CheckOverlap() *********************
  1302.  * Is the piece overlapping something?
  1303.  */
  1304. static char CheckOverlap(short x, short y, short inPiece, short inFlip)
  1305. {
  1306.   int g, j, k;
  1307.  
  1308.   for(g = 0; g < NUM_BLOCKS; g++)
  1309.     if(gCBlocks[inPiece][inFlip][g]) // some pieces do not have all the blocks
  1310.     {
  1311.       j = y + gYBlocks[inPiece][inFlip][g];
  1312.       k = x + gXBlocks[inPiece][inFlip][g];
  1313.       if(k < 0 || k > 9 || j > 19)
  1314.     return 1;
  1315.       else if(j >= 0 && ME.blockMap.b[j][k])
  1316.       return 1;
  1317.     }
  1318.   return 0;
  1319. }
  1320.  
  1321. static void PushUp(void)
  1322. {
  1323.   int x, e, d, g = 0;
  1324.  
  1325.   for(x = 0; x < 10; x++)
  1326.   {
  1327.     e = 666;
  1328.     for (g = 1; g < 20; g++)
  1329.     {
  1330.       d = e;
  1331.       e = ME.blockMap.b[g][x];
  1332.       if(e != d)
  1333.       {
  1334.     ME.blockMap.b[g - 1][x] = e;
  1335.     TeDrawBlock(x, g - 1, e);
  1336.       }
  1337.     }
  1338.     ME.blockMap.b[19][x] = BCOL_NEUTRAL;
  1339.   }
  1340.  
  1341.   ME.blockMap.b[19][rand() % 10] = 0;
  1342.   for(x = 0; x < 10; x++)
  1343.     TeDrawBlock(x, 19, ME.blockMap.b[19][x]);
  1344. }
  1345.  
  1346. /* ScrollDown() ************************
  1347.  * Nintendo's Tetris does this instead of CarbonStillGoing(). I'll put it back
  1348.  * in when I implement Purist Mode.
  1349.  */
  1350. /*
  1351. static void ScrollDown(short top, short bottom)
  1352. {
  1353.   short x, e, d, g;
  1354.  
  1355.   for(x = 0; x < 10; x++)
  1356.   {
  1357.     e = 66;
  1358.     for (g = bottom; g >= top; g--)
  1359.     {
  1360.       d = e;
  1361.       if(!g)
  1362.     e = 0;
  1363.       else
  1364.     e = ME.blockMap.b[g - 1][x];
  1365.       if(e != d || g == bottom)
  1366.       {
  1367.     if(e == -1)
  1368.       e = 0;
  1369.     ME.blockMap.b[g][x] = e;
  1370.     TeDrawBlock(x, g, e);
  1371.       }
  1372.     }
  1373.   }
  1374.   top++;
  1375. }
  1376. */
  1377.  
  1378. /* TeDrawBlock() **********************
  1379.  * Draws a colored block to the screen.  THIS MUST BE PORTED.
  1380.  */
  1381. static void TeDrawBlock(int x, int y, unsigned colour)
  1382. {
  1383.   int xDest = x * 8 + 88;
  1384.   int yDest = y * 8 + 48;
  1385.   int xSrc = (colour & BCON_ALL) << 3;
  1386.   int ySrc = (colour & BCOL_ALL) >> 1;
  1387.  
  1388.   if(y >= 0 && y < 20)
  1389.   {
  1390.     if(colour == 0 && g.backbits != NULL)
  1391.       blit(g.backbits, ME.seven->backBuf, xDest, yDest, xDest, yDest, 8, 8);
  1392.     else
  1393.       blit(tetbits, ME.seven->backBuf, xSrc, ySrc, xDest, yDest, 8, 8);
  1394.   }
  1395. }
  1396.  
  1397.