diff src/explode.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/explode.c	Fri Mar 13 00:39:12 2009 -0700
     1.3 @@ -0,0 +1,142 @@
     1.4 +/*
     1.5 +Bombl*ss extension for LOCKJAW Tetromino Game
     1.6 +Copr. 2007 Damian Yerrick
     1.7 +
     1.8 +*/
     1.9 +
    1.10 +
    1.11 +/*
    1.12 +
    1.13 +During falling, the auxiliary playfield p->c[][] contains a map of
    1.14 +individual regions used by the falling code.  But during explosion,
    1.15 +it serves a different purpose: counting the number of frames before
    1.16 +a given block is erased.
    1.17 +
    1.18 +*/
    1.19 +
    1.20 +const char explodeWidth[nLines] = {
    1.21 +  4, // megabomb
    1.22 +  3, 3, 3, 3, 4, 5, 5, 6, 6, 7  // 1-10 lines
    1.23 +};
    1.24 +const char explodeHeight[nLines] = {
    1.25 +  3, // megabomb
    1.26 +  0, 1, 2, 3, 4, 5, 5, 6, 6, 7  // 1-10 lines
    1.27 +};
    1.28 +
    1.29 +
    1.30 +/**
    1.31 + * Sets the number of frames before a block is erased based on
    1.32 + * the explosion.
    1.33 + * @param p the playfield
    1.34 + * @param x the column where the bomb is centered
    1.35 + * @param y the row where the bomb is centered
    1.36 + * @param bombColor the color of the bomb
    1.37 + * @param nLines the number of lines cleared, which determines the explosion size
    1.38 + */
    1.39 +void explodeAt(LJField *p, int x, int y, int bombColor, int nLines) {
    1.40 +  int boom = nLines;
    1.41 +
    1.42 +  if ((bombColor & COLOR_MASK) == BOMBCOLOR_SQUARE) {
    1.43 +    boom = 4;
    1.44 +  } else if (boom > 10) {
    1.45 +    boom = 10;
    1.46 +  }
    1.47 +
    1.48 +  int boomLeft = x - explodeWidth[boom];
    1.49 +  if (boomLeft < p->leftWall) {
    1.50 +    boomLeft = p->leftWall;
    1.51 +  }
    1.52 +  int boomRight = x + explodeWidth[boom];
    1.53 +  if (boomRight > p->rightWall - 1) {
    1.54 +    boomLeft = p->rightWall - 1;
    1.55 +  }
    1.56 +  int boomBottom = y - explodeHeight[boom];
    1.57 +  if (boomLeft < 0) {
    1.58 +    boomLeft = 0;
    1.59 +  }
    1.60 +  int boomTop = y + explodeHeight[boom];
    1.61 +  if (boomRight > LJ_PF_HT - 1) {
    1.62 +    boomLeft = LJ_PF_HT - 1;
    1.63 +  }
    1.64 +
    1.65 +  for (by = boomBottom; bx < boomTop; ++bx) {
    1.66 +    int dy = y - by;
    1.67 +    int dy2 = dy * dy;
    1.68 +    for (bx = boomLeft; bx < boomRight; ++bx) {
    1.69 +      int dx = x - bx;
    1.70 +      int dx2 = dx * dx;
    1.71 +      unsigned int time = (dx2 + dy2) / EXPLODE_SPEED + 2;
    1.72 +      if (p->c[y][x] > time) {
    1.73 +        p->c[y][x] = time;
    1.74 +      }
    1.75 +    }
    1.76 +  }
    1.77 +}
    1.78 +
    1.79 +static int blockIsBomb(unsigned int blk) {
    1.80 +  return (blk & COLOR_MASK) == BOMBCOLOR_NORMAL
    1.81 +          || (blk & COLOR_MASK) == BOMBCOLOR_SQUARE;
    1.82 +}
    1.83 +
    1.84 +/**
    1.85 + * Scans the exploding areas, erases blocks, and sets up bombs to explode.
    1.86 + * @param p the playfield
    1.87 + * @return the rows that were changed
    1.88 + */
    1.89 +LJBits explodeFrame(LJField *p) {
    1.90 +  LJBits changedRows = 0;
    1.91 +  LJBits changeAny = 0;
    1.92 +  
    1.93 +  int nLines = countRows(p->tempRows);
    1.94 +
    1.95 +  // first pass: destruction
    1.96 +  for (int y = 0; y < LJ_PF_HT; ++y) {
    1.97 +    for (int x = p->leftWall; x < p->rightWall; ++x) {
    1.98 +      if (p->c[y][x] == 1) {
    1.99 +        unsigned int blk = p->b[y][x];
   1.100 +        
   1.101 +        if (blk) {
   1.102 +          changedRows |= 1 << y;
   1.103 +          p->b[y][x] = 0;
   1.104 +          if (blockIsBomb(blk)) {
   1.105 +            explodeAt(p, x, y, blk, nLines);
   1.106 +          }
   1.107 +        }
   1.108 +      }
   1.109 +    }
   1.110 +  }
   1.111 +
   1.112 +  // second pass: countdown timer per block
   1.113 +  for (int y = 0; y < LJ_PF_HT; ++y) {
   1.114 +    for (int x = p->leftWall; x < p->rightWall; ++x) {
   1.115 +      if (p->c[y][x] > 0) {
   1.116 +        --p->c[y][x] > 0;
   1.117 +        changeAny = 1;
   1.118 +      }
   1.119 +    }
   1.120 +  }
   1.121 +
   1.122 +  return changeAny ? (1 << (LJ_PF_HT - 1)) : changedRows;
   1.123 +}
   1.124 +
   1.125 +/**
   1.126 + * Scans the cleared lines for bombs and marks c[] to trigger them.
   1.127 + * @param p the playfield, where tempRows holds the cleared lines
   1.128 + * @return the rows where bombs were triggered
   1.129 + */
   1.130 +LJBits triggerBombs(LJField *p) {
   1.131 +  LJBits bombRows = 0;
   1.132 +
   1.133 +  for (int y = 0; y < LJ_PF_HT; ++y) {
   1.134 +    if (p->tempRows & (1 << y)) {
   1.135 +      for (int x = p->leftWall; x < p->rightWall; ++x) {
   1.136 +        bool isBomb = blockIsBomb(p->b[y][x]);
   1.137 +        p->c[y][x] = isBomb;
   1.138 +        if (isBomb) {
   1.139 +          bombRows |= 1 << y;
   1.140 +        }
   1.141 +      }
   1.142 +    }
   1.143 +  }
   1.144 +  return bombRows;
   1.145 +}