summaryrefslogtreecommitdiff
authorandyq <andyq>2002-12-09 20:30:46 (UTC)
committer andyq <andyq>2002-12-09 20:30:46 (UTC)
commitb9a448e0687558c1cb79f801161966e15d589132 (patch) (side-by-side diff)
tree4f485b85b8bc03546008dd2003c75bf60f7acd9b
parentaccc4e231dc34744e75d32af77eeb98f46006c27 (diff)
downloadopie-b9a448e0687558c1cb79f801161966e15d589132.zip
opie-b9a448e0687558c1cb79f801161966e15d589132.tar.gz
opie-b9a448e0687558c1cb79f801161966e15d589132.tar.bz2
Added replay function and included own random method for replay functionality
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/games/sfcave/random.cpp179
-rw-r--r--noncore/games/sfcave/random.h19
-rw-r--r--noncore/games/sfcave/sfcave.cpp79
-rw-r--r--noncore/games/sfcave/sfcave.h12
-rw-r--r--noncore/games/sfcave/sfcave.pro4
5 files changed, 274 insertions, 19 deletions
diff --git a/noncore/games/sfcave/random.cpp b/noncore/games/sfcave/random.cpp
new file mode 100644
index 0000000..c4c10bb
--- a/dev/null
+++ b/noncore/games/sfcave/random.cpp
@@ -0,0 +1,179 @@
+/* -------------------------------------------------------------------------
+ * This is an ANSI C library for multi-stream random number generation.
+ * The use of this library is recommended as a replacement for the ANSI C
+ * rand() and srand() functions, particularly in simulation applications
+ * where the statistical 'goodness' of the random number generator is
+ * important. The library supplies 256 streams of random numbers; use
+ * SelectStream(s) to switch between streams indexed s = 0,1,...,255.
+ *
+ * The streams must be initialized. The recommended way to do this is by
+ * using the function PlantSeeds(x) with the value of x used to initialize
+ * the default stream and all other streams initialized automatically with
+ * values dependent on the value of x. The following convention is used
+ * to initialize the default stream:
+ * if x > 0 then x is the state
+ * if x < 0 then the state is obtained from the system clock
+ * if x = 0 then the state is to be supplied interactively.
+ *
+ * The generator used in this library is a so-called 'Lehmer random number
+ * generator' which returns a pseudo-random number uniformly distributed
+ * 0.0 and 1.0. The period is (m - 1) where m = 2,147,483,647 and the
+ * smallest and largest possible values are (1 / m) and 1 - (1 / m)
+ * respectively. For more details see:
+ *
+ * "Random Number Generators: Good Ones Are Hard To Find"
+ * Steve Park and Keith Miller
+ * Communications of the ACM, October 1988
+ *
+ * Name : rngs.c (Random Number Generation - Multiple Streams)
+ * Authors : Steve Park & Dave Geyer
+ * Language : ANSI C
+ * Latest Revision : 09-22-98
+ * -------------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include "random.h"
+
+#define MODULUS 2147483647 /* DON'T CHANGE THIS VALUE */
+#define MULTIPLIER 48271 /* DON'T CHANGE THIS VALUE */
+#define CHECK 399268537 /* DON'T CHANGE THIS VALUE */
+#define STREAMS 256 /* # of streams, DON'T CHANGE THIS VALUE */
+#define A256 22925 /* jump multiplier, DON'T CHANGE THIS VALUE */
+#define DEFAULT 123456789 /* initial seed, use 0 < DEFAULT < MODULUS */
+
+static long seed[STREAMS] = {DEFAULT}; /* current state of each stream */
+static int stream = 0; /* stream index, 0 is the default */
+static int initialized = 0; /* test for stream initialization */
+
+
+ double Random(void)
+/* ----------------------------------------------------------------
+ * Random returns a pseudo-random real number uniformly distributed
+ * between 0.0 and 1.0.
+ * ----------------------------------------------------------------
+ */
+{
+ const long Q = MODULUS / MULTIPLIER;
+ const long R = MODULUS % MULTIPLIER;
+ long t;
+
+ t = MULTIPLIER * (seed[stream] % Q) - R * (seed[stream] / Q);
+ if (t > 0)
+ seed[stream] = t;
+ else
+ seed[stream] = t + MODULUS;
+ return ((double) seed[stream] / MODULUS);
+}
+
+
+ void PlantSeeds(long x)
+/* ---------------------------------------------------------------------
+ * Use this function to set the state of all the random number generator
+ * streams by "planting" a sequence of states (seeds), one per stream,
+ * with all states dictated by the state of the default stream.
+ * The sequence of planted states is separated one from the next by
+ * 8,367,782 calls to Random().
+ * ---------------------------------------------------------------------
+ */
+{
+ const long Q = MODULUS / A256;
+ const long R = MODULUS % A256;
+ int j;
+ int s;
+
+ initialized = 1;
+ s = stream; /* remember the current stream */
+ SelectStream(0); /* change to stream 0 */
+ PutSeed(x); /* set seed[0] */
+ stream = s; /* reset the current stream */
+ for (j = 1; j < STREAMS; j++) {
+ x = A256 * (seed[j - 1] % Q) - R * (seed[j - 1] / Q);
+ if (x > 0)
+ seed[j] = x;
+ else
+ seed[j] = x + MODULUS;
+ }
+}
+
+
+ void PutSeed(long x)
+/* ---------------------------------------------------------------
+ * Use this function to set the state of the current random number
+ * generator stream according to the following conventions:
+ * if x > 0 then x is the state (unless too large)
+ * if x < 0 then the state is obtained from the system clock
+ * if x = 0 then the state is to be supplied interactively
+ * ---------------------------------------------------------------
+ */
+{
+ char ok = 0;
+
+ if (x > 0)
+ x = x % MODULUS; /* correct if x is too large */
+ if (x < 0)
+ x = ((unsigned long) time((time_t *) NULL)) % MODULUS;
+ if (x == 0)
+ while (!ok) {
+ printf("\nEnter a positive integer seed (9 digits or less) >> ");
+ scanf("%ld", &x);
+ ok = (0 < x) && (x < MODULUS);
+ if (!ok)
+ printf("\nInput out of range ... try again\n");
+ }
+ seed[stream] = x;
+}
+
+
+ void GetSeed(long *x)
+/* ---------------------------------------------------------------
+ * Use this function to get the state of the current random number
+ * generator stream.
+ * ---------------------------------------------------------------
+ */
+{
+ *x = seed[stream];
+}
+
+
+ void SelectStream(int index)
+/* ------------------------------------------------------------------
+ * Use this function to set the current random number generator
+ * stream -- that stream from which the next random number will come.
+ * ------------------------------------------------------------------
+ */
+{
+ stream = ((unsigned int) index) % STREAMS;
+ if ((initialized == 0) && (stream != 0)) /* protect against */
+ PlantSeeds(DEFAULT); /* un-initialized streams */
+}
+
+
+ void TestRandom(void)
+/* ------------------------------------------------------------------
+ * Use this (optional) function to test for a correct implementation.
+ * ------------------------------------------------------------------
+ */
+{
+ long i;
+ long x;
+ double u;
+ char ok = 0;
+
+ SelectStream(0); /* select the default stream */
+ PutSeed(1); /* and set the state to 1 */
+ for(i = 0; i < 10000; i++)
+ u = Random();
+ GetSeed(&x); /* get the new state value */
+ ok = (x == CHECK); /* and check for correctness */
+
+ SelectStream(1); /* select stream 1 */
+ PlantSeeds(1); /* set the state of all streams */
+ GetSeed(&x); /* get the state of stream 1 */
+ ok = ok && (x == A256); /* x should be the jump multiplier */
+ if (ok)
+ printf("\n The implementation of rngs.c is correct.\n\n");
+ else
+ printf("\n\a ERROR -- the implementation of rngs.c is not correct.\n\n");
+}
diff --git a/noncore/games/sfcave/random.h b/noncore/games/sfcave/random.h
new file mode 100644
index 0000000..4bc7c06
--- a/dev/null
+++ b/noncore/games/sfcave/random.h
@@ -0,0 +1,19 @@
+/* -----------------------------------------------------------------------
+ * Name : rngs.h (header file for the library file rngs.c)
+ * Author : Steve Park & Dave Geyer
+ * Language : ANSI C
+ * Latest Revision : 09-22-98
+ * -----------------------------------------------------------------------
+ */
+
+#if !defined( _RNGS_ )
+#define _RNGS_
+
+double Random(void);
+void PlantSeeds(long x);
+void GetSeed(long *x);
+void PutSeed(long x);
+void SelectStream(int index);
+void TestRandom(void);
+
+#endif
diff --git a/noncore/games/sfcave/sfcave.cpp b/noncore/games/sfcave/sfcave.cpp
index 788606f..b5bc736 100644
--- a/noncore/games/sfcave/sfcave.cpp
+++ b/noncore/games/sfcave/sfcave.cpp
@@ -1,52 +1,54 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
+#include <time.h>
#ifdef QWS
#include <qpe/qpeapplication.h>
#include <qpe/config.h>
#else
#include <qapplication.h>
#endif
#include "helpwindow.h"
#include "sfcave.h"
#define CAPTION "SFCave 1.8 by AndyQ"
#define UP_THRUST 0.6
#define NO_THRUST 0.8
#define MAX_DOWN_THRUST 4.0
#define MAX_UP_THRUST -3.5
// States
#define STATE_BOSS 0
#define STATE_RUNNING 1
#define STATE_CRASHING 2
#define STATE_CRASHED 3
#define STATE_NEWGAME 4
#define STATE_MENU 5
+#define STATE_REPLAY 6
// Menus
#define MENU_MAIN_MENU 0
#define MENU_OPTIONS_MENU 1
// Main Menu Options
#define MENU_START_GAME 0
#define MENU_OPTIONS 1
#define MENU_HELP 2
#define MENU_QUIT 3
// Option Menu Options
#define MENU_GAME_TYPE 0
#define MENU_GAME_DIFFICULTY 1
#define MENU_CLEAR_HIGHSCORES 2
#define MENU_BACK 3
#define NR_GAME_DIFFICULTIES 3
#define NR_GAME_TYPES 3
#define DIFICULTY_EASY 0
#define DIFICULTY_NORMAL 1
#define DIFICULTY_HARD 2
@@ -106,205 +108,241 @@ int main( int argc, char *argv[] )
QApplication a( argc, argv );
#endif
int speed = 3;
for ( int i = 0 ; i < argc ; ++i )
{
if ( strcmp( argv[i], "-s" ) == 0 )
{
if ( i+1 < argc )
speed = atoi( argv[i+1] );
}
}
SFCave app( speed );
a.setMainWidget( &app );
app.show();
app.start();
a.exec();
}
SFCave :: SFCave( int spd, QWidget *w, char *name )
: QMainWindow( w, name )
{
+ replayIt = 0;
#ifdef QWS
showMaximized();
#else
resize( 240, 284 );
#endif
sWidth = width();
sHeight = height();
segSize = sWidth/(MAPSIZE-1)+1;
currentMenuNr = 0;
currentGameType = 0;
currentGameDifficulty = 0;
setCaption( CAPTION );
showScoreZones = false;
#ifdef QWS
Config cfg( "sfcave" );
cfg.setGroup( "settings" );
QString key = "highScore_";
for ( int i = 0 ; i < 3 ; ++i )
{
for ( int j = 0 ; j < 3 ; ++j )
highestScore[i][j] = cfg.readNumEntry( key + gameTypes[i] + "_" + dificultyOption[j], 0 );
}
currentGameType = cfg.readNumEntry( "gameType", 0 );
currentGameDifficulty = cfg.readNumEntry( "difficulty", 0 );
#endif
speed = spd; // Change to 2 for PC
press = false;
offscreen = new QPixmap( sWidth, sHeight );
offscreen->fill( Qt::black );
- setUp();
+// setUp();
crashLineLength = -1;
+ state = STATE_MENU;
+ prevState = STATE_MENU;
gameTimer = new QTimer( this, "game timer" );
connect( gameTimer, SIGNAL( timeout() ),
this, SLOT( run() ) );
}
SFCave :: ~SFCave()
{
}
void SFCave :: start()
{
gameTimer->start( 10 );
}
+void SFCave :: setSeed( int seed )
+{
+ if ( seed == -1 )
+ currentSeed = ((unsigned long) time((time_t *) NULL));
+ else
+ currentSeed = seed;
+ PutSeed( currentSeed );
+}
+
int SFCave :: nextInt( int range )
{
- return rand() % range;
+ int val = (int)(Random( ) * range);
+
+ return val;
+
}
void SFCave :: setUp()
{
- state = STATE_MENU;
- prevState = STATE_MENU;
-
score = 0;
offset = 0;
nrFrames = 0;
dir = 1;
thrust = 0;
if ( CURRENT_GAME_TYPE == SFCAVE_GAME )
{
thrustUp = UpThrustVals[SFCAVE_GAME_TYPE][currentGameDifficulty];;
noThrust = DownThrustVals[SFCAVE_GAME_TYPE][currentGameDifficulty];;
maxUpThrust = MaxUpThrustVals[SFCAVE_GAME_TYPE][currentGameDifficulty];;
maxDownThrust = MaxDownThrustVals[SFCAVE_GAME_TYPE][currentGameDifficulty];;
}
else if ( CURRENT_GAME_TYPE == GATES_GAME )
{
thrustUp = UpThrustVals[GATES_GAME_TYPE][currentGameDifficulty];;
noThrust = DownThrustVals[GATES_GAME_TYPE][currentGameDifficulty];;
maxUpThrust = MaxUpThrustVals[GATES_GAME_TYPE][currentGameDifficulty];;
maxDownThrust = MaxDownThrustVals[GATES_GAME_TYPE][currentGameDifficulty];;
}
else
{
thrustUp = UpThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
noThrust = DownThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
maxUpThrust = MaxUpThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
maxDownThrust = MaxDownThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
}
crashLineLength = 0;
+ lastGateBottomY = 0;
user.setRect( 50, sWidth/2, 4, 4 );
blockWidth = 20;
blockHeight = 70;
gapHeight = initialGateGaps[currentGameDifficulty];
gateDistance = 75;
nextGate = nextInt( 50 ) + gateDistance;
for ( int i = 0 ; i < TRAILSIZE ; ++i )
{
trail[i].setX( -1 );
trail[i].setY( 0 );
}
if ( CURRENT_GAME_TYPE != FLY_GAME )
{
maxHeight = 50;
mapTop[0] = (int)(nextInt(50)) + 5;
mapBottom[0] = (int)(nextInt(50)) + 5;
for ( int i = 1 ; i < MAPSIZE ; ++i )
setPoint( i );
}
else
{
maxHeight = 100;
for ( int i = 0 ; i < MAPSIZE ; ++i )
mapBottom[i] = sHeight - 10;
}
for ( int i = 0 ; i < BLOCKSIZE ; ++i )
blocks[i].setY( -1 );
+
}
void SFCave :: run()
{
switch ( state )
{
case STATE_MENU:
displayMenu();
break;
case STATE_NEWGAME:
+ setSeed( -1 );
setUp();
draw();
state = STATE_RUNNING;
+ replay = false;
+ replayList.clear();
break;
+ case STATE_REPLAY:
+ setSeed( currentSeed );
+ setUp();
+ draw();
+ state = STATE_RUNNING;
+ replay = true;
+ if ( replayIt )
+ delete replayIt;
+ replayIt = new QListIterator<int>( replayList );
case STATE_BOSS:
drawBoss();
break;
case STATE_CRASHING:
case STATE_CRASHED:
draw();
break;
case STATE_RUNNING:
{
if ( nrFrames % 2 == 0 )
handleKeys();
// Apply Game rules
nrFrames ++;
+
+ if ( replay )
+ {
+ while( replayIt->current() && *(replayIt->current()) == nrFrames )
+ {
+ press = !press;
+ ++(*replayIt);
+ }
+ }
+
if ( CURRENT_GAME_TYPE == SFCAVE_GAME )
handleGameSFCave();
else if ( CURRENT_GAME_TYPE == GATES_GAME )
handleGameGates();
else if ( CURRENT_GAME_TYPE == FLY_GAME )
handleGameFly();
draw();
break;
}
}
}
void SFCave :: handleGameSFCave()
{
// Update score
if ( nrFrames % 5 == 0 )
score ++;
if ( nrFrames % 500 == 0 )
{
if ( maxHeight < sHeight - 100 )
{
maxHeight += 10;
@@ -502,54 +540,55 @@ void SFCave :: addBlock()
if ( blocks[i].y() == -1 )
{
int x = sWidth;
int y = mapTop[50] + (int)(nextInt(mapBottom[50] - mapTop[50] - blockHeight));
blocks[i].setRect( x, y, blockWidth, blockHeight );
break;
}
}
}
void SFCave :: addGate()
{
for ( int i = 0 ; i < BLOCKSIZE ; ++i )
{
if ( blocks[i].y() == -1 )
{
int x1 = sWidth;
int y1 = mapTop[50];
int b1Height = nextInt(mapBottom[50] - mapTop[50] - gapHeight);
// See if height between last gate and this one is too big
- if ( b1Height - 200 > lastGateBottomY )
+ if ( b1Height - 100 > lastGateBottomY )
b1Height -= 25;
- else if ( b1Height + 200 < lastGateBottomY )
+ else if ( b1Height + 100 < lastGateBottomY )
b1Height += 25;
lastGateBottomY = b1Height;
+
int x2 = sWidth;
int y2 = y1 + b1Height + gapHeight;
int b2Height = mapBottom[50] - y2;
blocks[i].setRect( x1, y1, blockWidth, b1Height );
blocks[i+1].setRect( x2, y2, blockWidth, b2Height );
break;
}
}
}
void SFCave :: setPoint( int point )
{
if ( nextInt(100) >= 80 )
dir *= -1;
mapTop[point] = mapTop[point-1] + (dir * nextInt( 5 ) );
if ( mapTop[point] < 0 )
{
mapTop[point] = 0;
dir *= -1;
}
@@ -752,95 +791,103 @@ void SFCave :: keyPressEvent( QKeyEvent *e )
}
else if ( currentMenuOption[currentMenuNr] == MENU_GAME_DIFFICULTY )
{
currentGameDifficulty ++;
if ( currentGameDifficulty == NR_GAME_DIFFICULTIES )
currentGameDifficulty = 0;
}
}
break;
case Qt::Key_Space:
case Qt::Key_Return:
case Qt::Key_Enter:
dealWithMenuSelection();
break;
}
}
else
{
switch( e->key() )
{
case Qt::Key_Up:
case Qt::Key_F9:
case Qt::Key_Space:
- press = true;
+ if ( !press )
+ {
+ press = true;
+ replayList.append( new int( nrFrames ) );
+ }
break;
case Qt::Key_M:
case Qt::Key_Return:
case Qt::Key_Enter:
if ( state == STATE_CRASHED )
state = STATE_MENU;
break;
case Qt::Key_Z:
showScoreZones = !showScoreZones;
break;
default:
e->ignore();
break;
}
}
}
void SFCave :: keyReleaseEvent( QKeyEvent *e )
{
if ( state == STATE_MENU )
{
}
else
{
switch( e->key() )
{
case Qt::Key_F9:
case Qt::Key_Space:
- press = false;
+ case Qt::Key_Up:
+ if ( press )
+ {
+ press = false;
+
+ replayList.append( new int( nrFrames ) );
+ }
break;
- case Qt::Key_Up:
- press = false;
-
case Qt::Key_R:
- case Qt::Key_Down:
if ( state == STATE_CRASHED )
{
- state = STATE_NEWGAME;
+ state = STATE_REPLAY;
}
- else
- movel = true;
break;
+ case Qt::Key_Down:
+ if ( state == STATE_CRASHED )
+ state = STATE_NEWGAME;
+ break;
default:
e->ignore();
break;
}
}
}
void SFCave :: displayMenu()
{
offscreen->fill( Qt::black );
QPainter p( offscreen );
p.setPen( Qt::white );
QFont f( "Helvetica", 16 );
p.setFont( f );
QFontMetrics fm = p.fontMetrics();
QString text = "SFCave";
p.drawText( (sWidth/2) - (fm.width( text )/2), 60, text );
text = "Written by Andy Qua";
diff --git a/noncore/games/sfcave/sfcave.h b/noncore/games/sfcave/sfcave.h
index 69a0e13..0d9a626 100644
--- a/noncore/games/sfcave/sfcave.h
+++ b/noncore/games/sfcave/sfcave.h
@@ -1,46 +1,55 @@
#include <qmainwindow.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qpoint.h>
#include <qrect.h>
#include <qtimer.h>
+#include <qlist.h>
-
+#include "random.h"
#define MAPSIZE 52
#define BLOCKSIZE 6
#define TRAILSIZE 30
+
+
class SFCave : public QMainWindow
{
Q_OBJECT
public:
int sWidth;
int sHeight;
int segSize;
+ int currentSeed;
+
+ QList<int> replayList;
+ QListIterator<int> *replayIt;
+ bool replay;
+
int blockWidth;
int blockHeight;
int gapHeight;
int state;
int prevState;
int speed;
int crashLineLength;
static double UpThrustVals[3][3];
static double DownThrustVals[3][3];
static double MaxUpThrustVals[3][3];
static double MaxDownThrustVals[3][3];
static int initialGateGaps[];
double thrustUp;
double noThrust;
double maxUpThrust;
double maxDownThrust;
int gateDistance;
int nextGate;
int lastGateBottomY;
static QString menuOptions[2][5];
@@ -58,48 +67,49 @@ public:
int score;
int highestScore[3][3];
int mapTop[MAPSIZE];
int mapBottom[MAPSIZE];
QRect blocks[BLOCKSIZE];
QRect user;
QPoint trail[TRAILSIZE];
int offset;
int maxHeight;
int nrFrames;
int dir;
bool showScoreZones;
bool press;
double thrust;
bool running;
SFCave( int speed = 3, QWidget *p = 0, char *name = 0 );
~SFCave();
void start();
+ void setSeed( int seed );
int nextInt( int range );
void setUp();
void handleGameSFCave();
void handleGameGates();
void handleGameFly();
bool checkFlyGameCollision();
void moveFlyGameLandscape();
void setFlyPoint( int point );
bool checkCollision();
void moveLandscape();
void addBlock();
void addGate();
void setPoint( int point );
void drawBoss();
void draw();
void handleKeys();
void displayMenu();
void dealWithMenuSelection();
void keyPressEvent( QKeyEvent *e );
void keyReleaseEvent( QKeyEvent *e );
void saveScore();
diff --git a/noncore/games/sfcave/sfcave.pro b/noncore/games/sfcave/sfcave.pro
index f4b9e5d..5f49330 100644
--- a/noncore/games/sfcave/sfcave.pro
+++ b/noncore/games/sfcave/sfcave.pro
@@ -1,9 +1,9 @@
TEMPLATE = app
CONFIG += qt warn_on release
DESTDIR = $(OPIEDIR)/bin
-SOURCES = sfcave.cpp helpwindow.cpp
-HEADERS = sfcave.h helpwindow.h
+SOURCES = sfcave.cpp helpwindow.cpp random.cpp
+HEADERS = sfcave.h helpwindow.h random.h
TARGET = sfcave
INCLUDEPATH += $(OPIEDIR)/include
DEPENDPATH += $(OPIEDIR)/include
LIBS += -lqpe