/* * * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ /* _______________________________________________________________________ ______________ S I L I C O N G R A P H I C S I N C . ____________ | | $Revision: 1.1.1.1 $ | | Classes : TsField::tricklePiece | TsField::stopPiece | TsField::collision | | Author : Dave Immel | ______________ S I L I C O N G R A P H I C S I N C . ____________ _______________________________________________________________________ */ //--------------------------- Include ---------------------------------- #include #include #include #include #include #include #include #include "TsPieces.h" #include "TsField.h" #define REMOVAL_HIGHLIGHT_DURATION 1.0 //////////////////////////////////////////////////////////////////////// // // Description: // This routine translates the current piece down in Y by a small // amount. The amount is determined by the current level of play. // If the piece crosses an integer boundary, a collision test must // be made. If a collision has occurred, the piece must stop at // the integer position, a check must be made to see if a whole // row may be removed, and a new piece is started. // // Use: public void TsField::tricklePiece( void *data, SoSensor * ) // //////////////////////////////////////////////////////////////////////// { TsField *field = (TsField *)data; SbTime elapsedTime; float tmpFraction, shiftDistance; time_t clockSeconds; long clockMSeconds; // System long // // Calculate the distance the piece should fall. This is calculated // given the change in time and the rate at which the piece is falling. // The distance is expressed as a value from 2.0 to 0.0. This represents // the intermediate distance from one integer position to the next. // elapsedTime.setToTimeOfDay(); elapsedTime -= field->wallClock; field->wallClock.setToTimeOfDay(); elapsedTime.getValue (clockSeconds, clockMSeconds); shiftDistance = (clockSeconds + clockMSeconds * 1e-6) * field->currentRate; tmpFraction = field->currentFraction - shiftDistance; if (tmpFraction >= 0.0) { // // Just translate down. // field->currentFraction = tmpFraction; } else while (tmpFraction < 0.0) { int newPosition[3], localPos[4], fieldPos[4]; // // The piece has crossed an integer boundary. // Temporarily shift the standard cube position down one level and // get the positions of the piece blocks at this new position. // newPosition[TS_X_AXIS] = field->standardPosition[TS_X_AXIS]; newPosition[TS_Y_AXIS] = field->standardPosition[TS_Y_AXIS] - 1; newPosition[TS_Z_AXIS] = field->standardPosition[TS_Z_AXIS]; (void)field->currentPiece->getPosition (localPos); field->getFieldPositions (field->numPieceBlocks, localPos, fieldPos, newPosition); // // Check this new position for a collision with blocks in the field // table and the floor. If there is a collision, stop the current // piece. // if (field->collision (field->numPieceBlocks, fieldPos)) { field->trickleSensor->unschedule(); field->stopPiece(); return; } // No collision. Finalize the standard cube position. --field->standardPosition[TS_Y_AXIS]; tmpFraction += 2.0; field->currentFraction = tmpFraction; } // Update the PieceYTranslation node to move the piece downwards. const SbVec3f &tpos = field->pieceYTranslation->translation.getValue (); SbVec3f spos; spos[0] = tpos[0]; spos[1] = tpos[1] - shiftDistance; spos[2] = tpos[2]; field->pieceYTranslation->translation.setValue (spos); } //////////////////////////////////////////////////////////////////////// // // Description: // This routine places blocks representing the current piece in // with the other static blocks on the field and fills in the // correct indices in the field table corresponding to the positions // of the blocks of the piece. // // The routine also checks the levels in which the current piece came // to rest and changes those rows to be gold. A sensor is scheduled // to elimate the rows. // // The routine ends the game if the current piece lands at the top of // the field. // // This routine gives the time the piece spent falling and the // number of rows removed to the scoreboard. // // If no rows have been removed, a new piece is put into play. // Use: private void TsField::stopPiece() // //////////////////////////////////////////////////////////////////////// { int numBlocks, localPos[4], fieldPos[4]; int height, rowIndex, i, j, tmp; // Initialize a list used for removing completed rows; for (i=0; i<3; i++) removalList[i] = -1; numRemovals = 0; // // Calculate the height and XZ position of each block based on the // standard cube location in the field and the local positions of // the blocks. Use the height to index into the level groups and the // XZ position to index into the nodelist of static block positions. // For each block add a child to the correct level group from the nodelist // of static block positions and fill in the field table for its position. // numBlocks = currentPiece->getPosition (localPos); getFieldPositions (numBlocks, localPos, fieldPos, standardPosition); for (i=0; i currentHeight) currentHeight = height; if (height >= totalHeight) { isGameOver = TRUE; return; } SoSeparator *level; level = (SoSeparator *)(otherBlocks->getChild(height)); level->addChild(staticBlock[rowIndex]); fieldTable[fieldPos[i]] = 1; // // Check the number of blocks now occupying the given level. // If the level is full, add the level on a sorted list as all // of its blocks will be removed. // if (level->getNumChildren() == (resolution*resolution+2)) { for (j=0; j0;) if (removalList[j] < removalList[j-1]) { tmp = removalList[j]; removalList[j] = removalList[j-1]; removalList[j-1] = tmp; } } } } // If the piece was dropped, restore the original falling rate. if (isDropping) { isDropping = FALSE; currentRate = saveRate; } // Award some points based on where the piece ended up. if (pointsEarned == 0) pointsEarned = standardPosition[TS_Y_AXIS] + 1; if (numRemovals > 0) { SoSeparator *levelSep; // Award some more points based on how many rows were removed. switch (numRemovals) { case 1: pointsEarned += 100; break; case 2: pointsEarned += 200; break; case 3: pointsEarned += 900; break; case 4: pointsEarned += 1600; break; } // Remove the falling piece from the scene graph fieldRoot->removeChild (fallingRoot); // // For each row to be removed, substitute a new material // for the normal level material. Then, schedule an alarm // sensor to go off after a time which will actually remove // the rows and animate the remaining rows downwards. // for (i=0; ireplaceChild(levelMaterial[removalList[i]], removalMaterial); } removalSensor->setTimeFromNow(SbTime(REMOVAL_HIGHLIGHT_DURATION)); removalSensor->schedule(); // The row removal code will add a new piece to the field, so control // can just return here. return; } else { } // Add a new piece to the playing field. addPoints( pointsEarned ); pointsEarned = 0; addPiece (); } //////////////////////////////////////////////////////////////////////// // // Description: // This routine checks to see if the current piece has collided with // other blocks in the field. // // Use: private SbBool TsField::collision( int numBlocks, // The number of blocks in the piece int *fieldPos) // The field positions of the blocks in the piece // //////////////////////////////////////////////////////////////////////// { int i; // // Check for intersection with another piece or the floor. // For each block in the piece, if its position is < 0 or // if the field is occupied at that position, a collision // has occurred. // for (i=0; i 0) return FALSE; } else if (standard[TS_X_AXIS] == (resolution-2)) { if ((pos[i] % 3) > 1) return FALSE; } if (standard[TS_X_AXIS] == -1) { if ((pos[i] % 3) < 1) return FALSE; } else if (standard[TS_X_AXIS] == -2) { if ((pos[i] % 3) < 2) return FALSE; } if (standard[TS_Z_AXIS] == (resolution-1)) { if ((pos[i] % 9) > 2) return FALSE; } else if (standard[TS_Z_AXIS] == (resolution-2)) { if ((pos[i] % 9) > 5) return FALSE; } else if (standard[TS_Z_AXIS] == -1) { if ((pos[i] % 9) < 3) return FALSE; } else if (standard[TS_Z_AXIS] == -2) { if ((pos[i] % 9) < 6) return FALSE; } } return TRUE; } //////////////////////////////////////////////////////////////////////// // // Description: // This routine returns a set of global positions given a set of // local positions and the location of the standard cube. // // Use: private void TsField::getFieldPositions( int numBlocks, // The number of blocks in the piece int *localPos, // The local positions of the blocks in the piece int *fieldPos, // The field positions of the blocks in the piece int *standard ) // The row, col, height of the standard cube // //////////////////////////////////////////////////////////////////////// { int i; for (i=0; i