local bushx = BUSH.get_pos_x();
local bushy = BUSH.get_pos_y();
for(local i = 0; i < 20; ++i) {
- BUSH.set_pos(bushx + rand() % 6 - 3, bushy);
+ BUSH.set_pos(bushx + RandomGenerator.rand1i(6) - 3, bushy);
wait(0.05);
}
}
#include "badguy/poisonivy.hpp"
#include "badguy/snowsnail.hpp"
#include "badguy/skullyhop.hpp"
+#include "random_generator.hpp"
Dispenser::Dispenser(const lisp::Lisp& reader)
{
Sector::current()->add_object(new SkullyHop(get_pos().x, get_pos().y+44, dir));
else if (badguy == "random")
{
- switch (rand()%7)
+ switch (systemRandom.rand(7))
{
case 0: Sector::current()->add_object(new SnowBall(get_pos().x, get_pos().y+32, dir)); break;
case 1: Sector::current()->add_object(new BouncingSnowball(get_pos().x, get_pos().y+32, dir)); break;
#include "object/tilemap.hpp"
#include "object/camera.hpp"
#include "tile.hpp"
+#include "random_generator.hpp"
#define LIFETIME 5
#define MOVETIME 0.75
sprite->set_action("flying");
physic.set_velocity_y(0);
//Set random initial speed and direction
- if ((rand() % 2) == 1) direction = 1; else direction = -1;
- int speed = (BASE_SPEED + (rand() % RAND_SPEED)) * direction;
+ direction = systemRandom.rand(2)? 1: -1;
+ int speed = (BASE_SPEED + (systemRandom.rand(RAND_SPEED))) * direction;
physic.set_velocity_x(speed);
movement_timer.start(MOVETIME);
lifetime.start(LIFETIME);
if (groundhit_pos_set) {
if (movement_timer.check()) {
if (direction == 1) direction = -1; else direction = 1;
- int speed = (BASE_SPEED + (rand() % RAND_SPEED)) * direction;
+ int speed = (BASE_SPEED + (systemRandom.rand(RAND_SPEED))) * direction;
physic.set_velocity_x(speed);
movement_timer.start(MOVETIME);
}
#include <config.h>
#include "skullyhop.hpp"
+#include "random_generator.hpp"
namespace {
const float VERTICAL_SPEED = 450; /**< y-speed when jumping */
physic.set_velocity_y(0);
sprite->set_action(dir == LEFT ? "standing-left" : "standing-right");
- float recover_time = MIN_RECOVER_TIME + (float)rand() / RAND_MAX * (MAX_RECOVER_TIME - MIN_RECOVER_TIME);
+ float recover_time = systemRandom.randf(MIN_RECOVER_TIME,MAX_RECOVER_TIME);
recover_timer.start(recover_time);
} else
if (newState == CHARGING) {
#include <config.h>
#include "stalactite.hpp"
+#include "random_generator.hpp"
static const int SHAKE_RANGE = 40;
static const float SHAKE_TIME = .8;
return;
if(state == STALACTITE_SHAKING) {
- sprite->draw(context, get_pos() + Vector((rand() % 6)-3, 0), LAYER_OBJECTS);
+ sprite->draw(context, get_pos() + Vector(systemRandom.rand(-3,3), 0), LAYER_OBJECTS);
} else {
sprite->draw(context, get_pos(), LAYER_OBJECTS);
}
#include <math.h>
#include "zeekling.hpp"
+#include "random_generator.hpp"
Zeekling::Zeekling(const lisp::Lisp& reader)
{
void
Zeekling::activate()
{
- speed = 130 + (rand() % 41);
+ speed = systemRandom.rand(130, 171);
if (set_direction) {dir = initial_direction;}
physic.set_velocity_x(dir == LEFT ? -speed : speed);
physic.enable_gravity(false);
#include "console.hpp"
#include "flip_level_transformer.hpp"
#include "trigger/secretarea_trigger.hpp"
+#include "random_generator.hpp"
// the engine will be run with a logical framerate of 64fps.
// We chose 64fps here because it is a power of 2, so 1/64 gives an "even"
currentsector->play_music(LEVEL_MUSIC);
- if(capture_file != "")
+ if(capture_file != "") {
+ int newSeed=0; // next run uses a new seed
+ while (newSeed == 0) // which is the next non-zero random num.
+ newSeed = systemRandom.rand();
+ config->random_seed = systemRandom.srand(newSeed);
+ log_info << "Next run uses random seed " <<config->random_seed <<std::endl;
record_demo(capture_file);
+ }
}
GameSession::~GameSession()
throw std::runtime_error(msg.str());
}
capture_file = filename;
+
+ char buf[30]; // save the seed in the demo file
+ sprintf(buf, "random_seed=%010d", config->random_seed);
+ for (int i=0; i==0 || buf[i-1]; i++)
+ capture_demo_stream->put(buf[i]);
}
void
Player& tux = *currentsector->player;
demo_controller = new CodeController();
tux.set_controller(demo_controller);
+
+ char buf[30]; // recall the seed from the demo file
+ int seed;
+ for (int i=0; i<30 && (i==0 || buf[i-1]); i++)
+ playback_demo_stream->get(buf[i]);
+ if (sscanf(buf, "random_seed=%010d", &seed) == 1) {
+ config->random_seed = seed; // save where it will be used
+ log_info << "Taking random seed " << seed << " from demo file" <<std::endl;
+ }
+ else {
+ playback_demo_stream->seekg(0); // old style w/o seed, restart at beg
+ log_info << "Demo file contains no random number" << std::endl;
+ }
}
void
sound_enabled = true;
music_enabled = true;
cheats_enabled = false;
+ random_seed = 0; // set by time(), by default (unless in config)
screenwidth = 800;
screenheight = 600;
config_lisp->get("show_fps", show_fps);
config_lisp->get("cheats", cheats_enabled);
+ config_lisp->get("random_seed", random_seed);
const lisp::Lisp* config_video_lisp = config_lisp->get_lisp("video");
if(config_video_lisp) {
bool music_enabled;
bool cheats_enabled;
+ int random_seed; // initial random seed. 0 ==> set from time()
+
/** this variable is set if supertux should start in a specific level */
std::string start_level;
bool enable_script_debugger;
#include "scripting/squirrel_util.hpp"
#include "file_system.hpp"
#include "physfs/physfs_sdl.hpp"
+#include "random_generator.hpp"
SDL_Surface* screen = 0;
JoystickKeyboardController* main_controller = 0;
;
}
+static void init_rand()
+{
+ const char *how = config->random_seed? ", user fixed.": ", from time().";
+
+ config->random_seed = systemRandom.srand(config->random_seed);
+
+ log_info << "Using random seed " << config->random_seed << how << std::endl;
+}
+
void init_video()
{
if(texture_manager != NULL)
try {
Console::instance = new Console();
- srand(time(0));
+// srand(time(0)); // this breaks repeatability in random numbers
init_physfs(argv[0]);
init_sdl();
// So we simply mount that path here...
std::string dir = FileSystem::dirname(config->start_level);
PHYSFS_addToSearchPath(dir.c_str(), true);
+
+ init_rand(); // play_demo sets seed, record_demo uses it
+
std::auto_ptr<GameSession> session
(new GameSession(FileSystem::basename(config->start_level)));
if(config->start_demo != "")
session->play_demo(config->start_demo);
+
if(config->record_demo != "")
session->record_demo(config->record_demo);
main_loop->push_screen(session.release());
} else {
+ init_rand();
main_loop->push_screen(new TitleScreen());
}
main_loop->run();
+
} catch(std::exception& e) {
log_fatal << "Unexpected exception: " << e.what() << std::endl;
result = 1;
#include "screen_fade.hpp"
#include "timer.hpp"
#include "player_status.hpp"
+#include "random_generator.hpp"
// the engine will be run with a logical framerate of 64fps.
// We chose 64fps here because it is a power of 2, so 1/64 gives an "even"
DrawingContext context;
unsigned int frame_count = 0;
+ unsigned int rand_prints = 0;
float fps_fps = 0;
Uint32 fps_ticks = SDL_GetTicks();
Uint32 fps_nextframe_ticks = SDL_GetTicks();
}
sound_manager->update();
+
+ // insert calls for debug (there are few rand calls otherwise)
+ if (0 && rand_prints++ % 20 == 0)
+ log_info << "== periodic rand() call " << systemRandom.rand() <<
+ " at frame " << rand_prints << "==" <<std::endl;
}
}
#include "main.hpp"
#include "video/drawing_context.hpp"
#include "audio/sound_manager.hpp"
+#include "random_generator.hpp"
Fireworks::Fireworks()
{
if(timer.check()) {
Sector* sector = Sector::current();
Vector pos = sector->camera->get_translation();
- pos += Vector(SCREEN_WIDTH * ((float) rand() / RAND_MAX),
- SCREEN_HEIGHT/2 * ((float) rand() / RAND_MAX));
+ pos += Vector(systemRandom.randf(SCREEN_WIDTH),
+ systemRandom.randf(SCREEN_HEIGHT/2));
- int r = rand() % 255;
- int g = rand() % 255;
- float red = r / 255.0;
- float green = g / 255.0;
+ float red = systemRandom.randf(1.0);
+ float green = systemRandom.randf(1.0);
//float red = 0.7;
//float green = 0.9;
(void) red;
Vector(0, 0), 45, Color(red, green, 0), 3, 1.3,
LAYER_FOREGROUND1+1));
sound_manager->play("sounds/fireworks.wav");
- timer.start(((float) rand() / RAND_MAX) + .5);
+ timer.start(systemRandom.randf(1.0, 1.5));
}
}
#include "video/drawing_context.hpp"
#include "camera.hpp"
#include "main.hpp"
+#include "random_generator.hpp"
BouncyCoin::BouncyCoin(const Vector& pos)
: position(pos)
BrokenBrick::draw(DrawingContext& context)
{
sprite->draw_part(context,
- Vector(rand() % 16, rand() % 16), Vector(16, 16),
+ Vector(systemRandom.rand(16), systemRandom.rand(16)), Vector(16, 16),
position, LAYER_OBJECTS + 1);
}
#include "sector.hpp"
#include "camera.hpp"
#include "main.hpp"
+#include "random_generator.hpp"
Particles::Particles(const Vector& epicenter, int min_angle, int max_angle,
const Vector& initial_velocity, const Vector& acceleration, int number,
Particle* particle = new Particle;
particle->pos = epicenter;
- float angle = ((rand() % (max_angle-min_angle))+min_angle)
- * (M_PI / 180); // convert to radius
+ float angle = systemRandom.rand(min_angle, max_angle)
+ * (M_PI / 180); // convert to radius (radians?)
particle->vel.x = /*fabs*/(sin(angle)) * initial_velocity.x;
// if(angle >= M_PI && angle < M_PI*2)
// particle->vel.x *= -1; // work around to fix signal
#include "resources.hpp"
#include "main.hpp"
#include "object/camera.hpp"
+#include "random_generator.hpp"
ParticleSystem::ParticleSystem()
{
size_t snowflakecount = size_t(virtual_width/10.0);
for(size_t i=0; i<snowflakecount; ++i) {
SnowParticle* particle = new SnowParticle;
- particle->pos.x = fmodf(rand(), virtual_width);
- particle->pos.y = fmodf(rand(), SCREEN_HEIGHT);
- int snowsize = rand() % 3;
+ particle->pos.x = systemRandom.randf(virtual_width);
+ particle->pos.y = systemRandom.randf(SCREEN_HEIGHT);
+ int snowsize = systemRandom.rand(3);
particle->texture = snowimages[snowsize];
do {
- particle->speed = snowsize*.2 + (float(rand()%10)*.4);
+ particle->speed = snowsize*.2 + systemRandom.randf(3.6);
} while(particle->speed < 1);
particle->speed *= 10; // gravity
particle->pos.y += particle->speed * elapsed_time;
if(particle->pos.y > SCREEN_HEIGHT + Sector::current()->camera->get_translation().y) {
particle->pos.y = fmodf(particle->pos.y , virtual_height);
- particle->pos.x = rand() % int(virtual_width);
+ particle->pos.x = systemRandom.rand((int)virtual_width);
}
}
}
size_t ghostcount = 2;
for(size_t i=0; i<ghostcount; ++i) {
GhostParticle* particle = new GhostParticle;
- particle->pos.x = fmodf(rand(), virtual_width);
- particle->pos.y = fmodf(rand(), SCREEN_HEIGHT);
- int size = rand() % 2;
+ particle->pos.x = systemRandom.randf(virtual_width);
+ particle->pos.y = systemRandom.randf(SCREEN_HEIGHT);
+ int size = systemRandom.rand(2);
particle->texture = ghosts[size];
do {
- particle->speed = size*.2 + (float(rand()%10)*.4);
+ particle->speed = size*.2 + systemRandom.randf(3.6);
} while(particle->speed < 1);
particle->speed *= 50;
particles.push_back(particle);
particle->pos.x -= particle->speed * elapsed_time;
if(particle->pos.y > SCREEN_HEIGHT) {
particle->pos.y = fmodf(particle->pos.y , virtual_height);
- particle->pos.x = rand() % int(virtual_width);
+ particle->pos.x = systemRandom.rand((int)virtual_width);
}
}
}
// create some random clouds
for(size_t i=0; i<15; ++i) {
CloudParticle* particle = new CloudParticle;
- particle->pos.x = rand() % int(virtual_width);
- particle->pos.y = rand() % int(virtual_height);
+ particle->pos.x = systemRandom.rand((int)virtual_width);
+ particle->pos.y = systemRandom.rand((int)virtual_height);
particle->texture = cloudimage;
- particle->speed = -float(25 + rand() % 30);
+ particle->speed = -systemRandom.randf(25, 54);
particles.push_back(particle);
}
#include "object/camera.hpp"
#include "object/rainsplash.hpp"
#include "badguy/bomb.hpp"
+#include "random_generator.hpp"
//TODO: Find a way to make rain collide with objects like bonus blocks
// Add an option to set rain strength
size_t raindropcount = size_t(virtual_width/6.0);
for(size_t i=0; i<raindropcount; ++i) {
RainParticle* particle = new RainParticle;
- particle->pos.x = rand() % int(virtual_width);
- particle->pos.y = rand() % int(virtual_height);
- int rainsize = rand() % 2;
+ particle->pos.x = systemRandom.rand(int(virtual_width));
+ particle->pos.y = systemRandom.rand(int(virtual_height));
+ int rainsize = systemRandom.rand(2);
particle->texture = rainimages[rainsize];
do {
- particle->speed = (rainsize+1)*45 + (float(rand()%10)*.4);
+ particle->speed = (rainsize+1)*45 + systemRandom.randf(3.6);
} while(particle->speed < 1);
particle->speed *= 10; // gravity
Sector::current()->add_object(new RainSplash(Vector(splash_x, splash_y),vertical));
} */
}
- int new_x = (rand() % int(virtual_width)) + int(abs_x);
+ int new_x = systemRandom.rand(int(virtual_width)) + int(abs_x);
int new_y = 0;
//FIXME: Don't move particles over solid tiles
particle->pos.x = new_x;
size_t cometcount = 2;
for(size_t i=0; i<cometcount; ++i) {
CometParticle* particle = new CometParticle;
- particle->pos.x = rand() % int(virtual_width);
- particle->pos.y = rand() % int(virtual_height);
- int cometsize = rand() % 2;
+ particle->pos.x = systemRandom.rand(int(virtual_width));
+ particle->pos.y = systemRandom.rand(int(virtual_height));
+ int cometsize = systemRandom.rand(2);
particle->texture = cometimages[cometsize];
do {
- particle->speed = (cometsize+1)*30 + (float(rand()%10)*.4);
+ particle->speed = (cometsize+1)*30 + systemRandom.randf(3.6);
} while(particle->speed < 1);
particle->speed *= 10; // gravity
if ((particle->pos.y <= SCREEN_HEIGHT + abs_y) && (col >= 1)) {
Sector::current()->add_object(new Bomb(particle->pos, LEFT));
}
- int new_x = (rand() % int(virtual_width)) + int(abs_x);
+ int new_x = systemRandom.rand(int(virtual_width)) + int(abs_x);
int new_y = 0;
//FIXME: Don't move particles over solid tiles
particle->pos.x = new_x;
#include "player_status.hpp"
#include "log.hpp"
#include "falling_coin.hpp"
+#include "random_generator.hpp"
static const int TILES_FOR_BUTTJUMP = 3;
static const float SHOOTING_TIME = .150;
Player::expose(HSQUIRRELVM vm, int table_idx)
{
Scripting::Player* interface = static_cast<Scripting::Player*> (this);
- expose_object(vm, table_idx, interface, "Tux", false);
+ Scripting::expose_object(vm, table_idx, interface, "Tux", false);
}
void
}
else
{
- srand(time(0));
+// systemRandom.srand(time(0));// 060422 PAK: gone for repeatibility
int i;
for (i = 0; (i < 5) && (i < player_status->coins); i++)
{
// the numbers: starting x, starting y, velocity y
- Sector::current()->add_object(new FallingCoin(get_pos() + Vector(rand()%5, rand()%50 - 32), rand()%200 - 100));
+ Sector::current()->add_object(new FallingCoin(get_pos() +
+ Vector(systemRandom.rand(5), systemRandom.rand(-32,18)),
+ systemRandom.rand(-100,100)));
}
physic.enable_gravity(true);
physic.set_acceleration(0, 0);
#include "resources.hpp"
#include "sprite/sprite_manager.hpp"
#include "sprite/sprite.hpp"
+#include "random_generator.hpp"
static const float CRACKTIME = 0.3;
static const float FALLTIME = 0.8;
Vector pos = get_pos();
// shacking
if(timer.get_timegone() > CRACKTIME) {
- pos.x += (rand() % 6) - 3;
+ pos.x += systemRandom.rand(-3, 3);
}
sprite->draw(context, pos, LAYER_TILES);
#include "resources.hpp"
#include "sprite/sprite_manager.hpp"
#include "sprite/sprite.hpp"
+#include "random_generator.hpp"
static const float CRACKTIME = 0.3;
static const float FALLTIME = 0.8;
Vector pos = get_pos();
// shacking
if(timer.get_timegone() > CRACKTIME) {
- pos.x += (rand() % 6) - 3;
+ pos.x += systemRandom.rand(-3, 3);
}
sprite->draw(context, pos, LAYER_TILES);
--- /dev/null
+// $Id$
+//
+// A strong random number generator
+//
+// Copyright (C) 2006 Allen King
+// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
+// Copyright (C) 1983, 1993 The Regents of the University of California.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the project nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+
+// Transliterated into C++ Allen King 060417, from sources on
+// http://www.jbox.dk/sanos/source/lib/random.c.html
+
+
+
+#include <stdexcept>
+#include "random_generator.hpp"
+#include "scripting/squirrel_util.hpp"
+
+RandomGenerator systemRandom; // global random number generator
+
+RandomGenerator::RandomGenerator() {
+ assert(sizeof(int) >= 4);
+ initialized = 0;
+ initialize();
+}
+
+RandomGenerator::~RandomGenerator() {
+}
+
+int RandomGenerator::srand(int x) {
+ while (x == 0) // random seed of zero means
+ x = time(0); // randomize with time
+ assert(x < RAND_MAX); // only allow posative 31-bit seeds
+ assert(sizeof(int) >= 4);
+ srandom(x);
+ return x; // let caller know seed used
+}
+
+int RandomGenerator::rand() { return random(); }
+
+int RandomGenerator::rand(int v) {
+ assert(v != 0 && v <= RAND_MAX); // illegal arg: 0 or too big
+ return RandomGenerator::random() % v;
+}
+
+int RandomGenerator::rand(int u, int v) {
+ assert(v > u);
+ return u + RandomGenerator::rand(v-u);
+}
+
+double RandomGenerator::randf(double v) {
+ float rv;
+ while ((rv = (double)RandomGenerator::random() / RAND_MAX * v) >= v)
+ ; // never return v!
+ return rv;
+}
+
+double RandomGenerator::randf(double u, double v) {
+ return u + RandomGenerator::randf(v-u);
+}
+
+//-----------------------------------------------------------------------
+//
+// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
+// Copyright (C) 1983, 1993 The Regents of the University of California.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the project nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+
+//**#include <os.h>
+
+//
+// An improved random number generation package. In addition to the standard
+// rand()/srand() like interface, this package also has a special state info
+// interface. The initstate() routine is called with a seed, an array of
+// bytes, and a count of how many bytes are being passed in; this array is
+// then initialized to contain information for random number generation with
+// that much state information. Good sizes for the amount of state
+// information are 32, 64, 128, and 256 bytes. The state can be switched by
+// calling the setstate() routine with the same array as was initiallized
+// with initstate(). By default, the package runs with 128 bytes of state
+// information and generates far better random numbers than a linear
+// congruential generator. If the amount of state information is less than
+// 32 bytes, a simple linear congruential R.N.G. is used.
+//
+// Internally, the state information is treated as an array of longs; the
+// zeroeth element of the array is the type of R.N.G. being used (small
+// integer); the remainder of the array is the state information for the
+// R.N.G. Thus, 32 bytes of state information will give 7 longs worth of
+// state information, which will allow a degree seven polynomial. (Note:
+// the zeroeth word of state information also has some other information
+// stored in it -- see setstate() for details).
+//
+// The random number generation technique is a linear feedback shift register
+// approach, employing trinomials (since there are fewer terms to sum up that
+// way). In this approach, the least significant bit of all the numbers in
+// the state table will act as a linear feedback shift register, and will
+// have period 2^deg - 1 (where deg is the degree of the polynomial being
+// used, assuming that the polynomial is irreducible and primitive). The
+// higher order bits will have longer periods, since their values are also
+// influenced by pseudo-random carries out of the lower bits. The total
+// period of the generator is approximately deg*(2**deg - 1); thus doubling
+// the amount of state information has a vast influence on the period of the
+// generator. Note: the deg*(2**deg - 1) is an approximation only good for
+// large deg, when the period of the shift is the dominant factor.
+// With deg equal to seven, the period is actually much longer than the
+// 7*(2**7 - 1) predicted by this formula.
+//
+// Modified 28 December 1994 by Jacob S. Rosenberg.
+//
+
+//
+// For each of the currently supported random number generators, we have a
+// break value on the amount of state information (you need at least this
+// many bytes of state info to support this random number generator), a degree
+// for the polynomial (actually a trinomial) that the R.N.G. is based on, and
+// the separation between the two lower order coefficients of the trinomial.
+
+void RandomGenerator::initialize() {
+
+#define NSHUFF 100 // To drop part of seed -> 1st value correlation
+
+//static long degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
+//static long seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
+
+ degrees[0] = DEG_0;
+ degrees[1] = DEG_1;
+ degrees[2] = DEG_2;
+ degrees[3] = DEG_3;
+ degrees[4] = DEG_4;
+
+ seps [0] = SEP_0;
+ seps [1] = SEP_1;
+ seps [2] = SEP_2;
+ seps [3] = SEP_3;
+ seps [4] = SEP_4;
+
+//
+// Initially, everything is set up as if from:
+//
+// initstate(1, randtbl, 128);
+//
+// Note that this initialization takes advantage of the fact that srandom()
+// advances the front and rear pointers 10*rand_deg times, and hence the
+// rear pointer which starts at 0 will also end up at zero; thus the zeroeth
+// element of the state information, which contains info about the current
+// position of the rear pointer is just
+//
+// MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
+
+ randtbl[ 0] = TYPE_3;
+ randtbl[ 1] = 0x991539b1;
+ randtbl[ 2] = 0x16a5bce3;
+ randtbl[ 3] = 0x6774a4cd;
+ randtbl[ 4] = 0x3e01511e;
+ randtbl[ 5] = 0x4e508aaa;
+ randtbl[ 6] = 0x61048c05;
+ randtbl[ 7] = 0xf5500617;
+ randtbl[ 8] = 0x846b7115;
+ randtbl[ 9] = 0x6a19892c;
+ randtbl[10] = 0x896a97af;
+ randtbl[11] = 0xdb48f936;
+ randtbl[12] = 0x14898454;
+ randtbl[13] = 0x37ffd106;
+ randtbl[14] = 0xb58bff9c;
+ randtbl[15] = 0x59e17104;
+ randtbl[16] = 0xcf918a49;
+ randtbl[17] = 0x09378c83;
+ randtbl[18] = 0x52c7a471;
+ randtbl[19] = 0x8d293ea9;
+ randtbl[20] = 0x1f4fc301;
+ randtbl[21] = 0xc3db71be;
+ randtbl[22] = 0x39b44e1c;
+ randtbl[23] = 0xf8a44ef9;
+ randtbl[24] = 0x4c8b80b1;
+ randtbl[25] = 0x19edc328;
+ randtbl[26] = 0x87bf4bdd;
+ randtbl[27] = 0xc9b240e5;
+ randtbl[28] = 0xe9ee4b1b;
+ randtbl[29] = 0x4382aee7;
+ randtbl[30] = 0x535b6b41;
+ randtbl[31] = 0xf3bec5da;
+
+// static long randtbl[DEG_3 + 1] =
+// {
+// TYPE_3;
+// 0x991539b1, 0x16a5bce3, 0x6774a4cd, 0x3e01511e, 0x4e508aaa, 0x61048c05,
+// 0xf5500617, 0x846b7115, 0x6a19892c, 0x896a97af, 0xdb48f936, 0x14898454,
+// 0x37ffd106, 0xb58bff9c, 0x59e17104, 0xcf918a49, 0x09378c83, 0x52c7a471,
+// 0x8d293ea9, 0x1f4fc301, 0xc3db71be, 0x39b44e1c, 0xf8a44ef9, 0x4c8b80b1,
+// 0x19edc328, 0x87bf4bdd, 0xc9b240e5, 0xe9ee4b1b, 0x4382aee7, 0x535b6b41,
+// 0xf3bec5da
+// };
+
+
+//
+// fptr and rptr are two pointers into the state info, a front and a rear
+// pointer. These two pointers are always rand_sep places aparts, as they
+// cycle cyclically through the state information. (Yes, this does mean we
+// could get away with just one pointer, but the code for random() is more
+// efficient this way). The pointers are left positioned as they would be
+// from the call
+//
+// initstate(1, randtbl, 128);
+//
+// (The position of the rear pointer, rptr, is really 0 (as explained above
+// in the initialization of randtbl) because the state table pointer is set
+// to point to randtbl[1] (as explained below).
+//
+
+ fptr = &randtbl[SEP_3 + 1];
+ rptr = &randtbl[1];
+
+//
+// The following things are the pointer to the state information table, the
+// type of the current generator, the degree of the current polynomial being
+// used, and the separation between the two pointers. Note that for efficiency
+// of random(), we remember the first location of the state information, not
+// the zeroeth. Hence it is valid to access state[-1], which is used to
+// store the type of the R.N.G. Also, we remember the last location, since
+// this is more efficient than indexing every time to find the address of
+// the last element to see if the front and rear pointers have wrapped.
+//
+
+ state = &randtbl[1];
+ rand_type = TYPE_3;
+ rand_deg = DEG_3;
+ rand_sep = SEP_3;
+ end_ptr = &randtbl[DEG_3 + 1];
+
+}
+
+//
+// Compute x = (7^5 * x) mod (2^31 - 1)
+// wihout overflowing 31 bits:
+// (2^31 - 1) = 127773 * (7^5) + 2836
+// From "Random number generators: good ones are hard to find",
+// Park and Miller, Communications of the ACM, vol. 31, no. 10,
+// October 1988, p. 1195.
+//
+
+__inline static long good_rand(long x)
+{
+ long hi, lo;
+
+ // Can't be initialized with 0, so use another value.
+ if (x == 0) x = 123459876;
+ hi = x / 127773;
+ lo = x % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x < 0) x += 0x7fffffff;
+ return x;
+}
+
+//
+// srandom
+//
+// Initialize the random number generator based on the given seed. If the
+// type is the trivial no-state-information type, just remember the seed.
+// Otherwise, initializes state[] based on the given "seed" via a linear
+// congruential generator. Then, the pointers are set to known locations
+// that are exactly rand_sep places apart. Lastly, it cycles the state
+// information a given number of times to get rid of any initial dependencies
+// introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
+// for default usage relies on values produced by this routine.
+
+void RandomGenerator::srandom(unsigned long x)
+{
+ long i, lim;
+
+ state[0] = x;
+ if (rand_type == TYPE_0)
+ lim = NSHUFF;
+ else
+ {
+ for (i = 1; i < rand_deg; i++) state[i] = good_rand(state[i - 1]);
+ fptr = &state[rand_sep];
+ rptr = &state[0];
+ lim = 10 * rand_deg;
+ }
+
+ initialized = 1;
+ for (i = 0; i < lim; i++) random();
+}
+
+#ifdef NOT_FOR_SUPERTUX // use in supertux doesn't require these methods,
+ // which are not portable to as many platforms as
+ // SDL. The cost is that the variability of the
+ // initial seed is reduced to only 32 bits of
+ // randomness, seemingly enough. PAK 060420
+//
+// srandomdev
+//
+// Many programs choose the seed value in a totally predictable manner.
+// This often causes problems. We seed the generator using the much more
+// secure random() interface. Note that this particular seeding
+// procedure can generate states which are impossible to reproduce by
+// calling srandom() with any value, since the succeeding terms in the
+// state buffer are no longer derived from the LC algorithm applied to
+// a fixed seed.
+
+void RandomGenerator::srandomdev()
+{
+ int fd, done;
+ size_t len;
+
+ if (rand_type == TYPE_0)
+ len = sizeof state[0];
+ else
+ len = rand_deg * sizeof state[0];
+
+ done = 0;
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd >= 0)
+ {
+ if (read(fd, state, len) == len) done = 1;
+ close(fd);
+ }
+
+ if (!done)
+ {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ srandom(tv.tv_sec ^ tv.tv_usec);
+ return;
+ }
+
+ if (rand_type != TYPE_0)
+ {
+ fptr = &state[rand_sep];
+ rptr = &state[0];
+ }
+ initialized = 1;
+}
+
+//
+// initstate
+//
+// Initialize the state information in the given array of n bytes for future
+// random number generation. Based on the number of bytes we are given, and
+// the break values for the different R.N.G.'s, we choose the best (largest)
+// one we can and set things up for it. srandom() is then called to
+// initialize the state information.
+//
+// Note that on return from srandom(), we set state[-1] to be the type
+// multiplexed with the current value of the rear pointer; this is so
+// successive calls to initstate() won't lose this information and will be
+// able to restart with setstate().
+//
+// Note: the first thing we do is save the current state, if any, just like
+// setstate() so that it doesn't matter when initstate is called.
+//
+// Returns a pointer to the old state.
+//
+
+char * RandomGenerator::initstate(unsigned long seed, char *arg_state, long n)
+{
+ char *ostate = (char *) (&state[-1]);
+ long *long_arg_state = (long *) arg_state;
+
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+
+ if (n < BREAK_0) return NULL;
+
+ if (n < BREAK_1)
+ {
+ rand_type = TYPE_0;
+ rand_deg = DEG_0;
+ rand_sep = SEP_0;
+ }
+ else if (n < BREAK_2)
+ {
+ rand_type = TYPE_1;
+ rand_deg = DEG_1;
+ rand_sep = SEP_1;
+ }
+ else if (n < BREAK_3)
+ {
+ rand_type = TYPE_2;
+ rand_deg = DEG_2;
+ rand_sep = SEP_2;
+ }
+ else if (n < BREAK_4)
+ {
+ rand_type = TYPE_3;
+ rand_deg = DEG_3;
+ rand_sep = SEP_3;
+ }
+ else
+ {
+ rand_type = TYPE_4;
+ rand_deg = DEG_4;
+ rand_sep = SEP_4;
+ }
+
+ state = (long *) (long_arg_state + 1); // First location
+ end_ptr = &state[rand_deg]; // Must set end_ptr before srandom
+ srandom(seed);
+
+ if (rand_type == TYPE_0)
+ long_arg_state[0] = rand_type;
+ else
+ long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type;
+
+ initialized = 1;
+ return ostate;
+}
+
+//
+// setstate
+//
+// Restore the state from the given state array.
+//
+// Note: it is important that we also remember the locations of the pointers
+// in the current state information, and restore the locations of the pointers
+// from the old state information. This is done by multiplexing the pointer
+// location into the zeroeth word of the state information.
+//
+// Note that due to the order in which things are done, it is OK to call
+// setstate() with the same state as the current state.
+//
+// Returns a pointer to the old state information.
+//
+
+char * RandomGenerator::setstate(char *arg_state)
+{
+ long *new_state = (long *) arg_state;
+ long type = new_state[0] % MAX_TYPES;
+ long rear = new_state[0] / MAX_TYPES;
+ char *ostate = (char *) (&state[-1]);
+
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+
+ switch(type)
+ {
+ case TYPE_0:
+ case TYPE_1:
+ case TYPE_2:
+ case TYPE_3:
+ case TYPE_4:
+ rand_type = type;
+ rand_deg = degrees[type];
+ rand_sep = seps[type];
+ break;
+ }
+
+ state = (long *) (new_state + 1);
+ if (rand_type != TYPE_0)
+ {
+ rptr = &state[rear];
+ fptr = &state[(rear + rand_sep) % rand_deg];
+ }
+ end_ptr = &state[rand_deg]; // Set end_ptr too
+
+ initialized = 1;
+ return ostate;
+}
+#endif //NOT_FOR_SUPERTUX
+//
+// random:
+//
+// If we are using the trivial TYPE_0 R.N.G., just do the old linear
+// congruential bit. Otherwise, we do our fancy trinomial stuff, which is
+// the same in all the other cases due to all the global variables that have
+// been set up. The basic operation is to add the number at the rear pointer
+// into the one at the front pointer. Then both pointers are advanced to
+// the next location cyclically in the table. The value returned is the sum
+// generated, reduced to 31 bits by throwing away the "least random" low bit.
+//
+// Note: the code takes advantage of the fact that both the front and
+// rear pointers can't wrap on the same call by not testing the rear
+// pointer if the front one has wrapped.
+//
+// Returns a 31-bit random number.
+//
+
+long RandomGenerator::random()
+{
+ long i;
+ long *f, *r;
+ if (!initialized) {
+ throw std::runtime_error("uninitialized RandomGenerator object");
+ }
+
+ if (rand_type == TYPE_0)
+ {
+ i = state[0];
+ state[0] = i = (good_rand(i)) & 0x7fffffff;
+ }
+ else
+ {
+ f = fptr; r = rptr;
+ *f += *r;
+ i = (*f >> 1) & 0x7fffffff; // Chucking least random bit
+ if (++f >= end_ptr)
+ {
+ f = state;
+ ++r;
+ }
+ else if (++r >= end_ptr)
+ r = state;
+
+ fptr = f; rptr = r;
+ }
+
+ return i;
+}
--- /dev/null
+// $Id$
+//
+// A strong random number generator
+//
+// Copyright (C) 2006 Allen King
+// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
+// Copyright (C) 1983, 1993 The Regents of the University of California.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the project nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+
+#ifndef __RANDOM_GENERATOR__
+#define __RANDOM_GENERATOR__
+
+#include "scripting/random_generator.hpp"
+#include "script_interface.hpp"
+
+class RandomGenerator : public Scripting::RandomGenerator
+{
+private:
+// Array versions of the above information to make code run faster --
+// relies on fact that TYPE_i == i.
+ static const int TYPE_0 = 0; // Linear congruential
+ static const int BREAK_0 = 8;
+ static const int DEG_0 = 0;
+ static const int SEP_0 = 0;
+
+ static const int TYPE_1 = 1; // x**7 + x**3 + 1
+ static const int BREAK_1 = 32;
+ static const int DEG_1 = 7;
+ static const int SEP_1 = 3;
+
+ static const int TYPE_2 = 2; // x**15 + x + 1
+ static const int BREAK_2 = 64;
+ static const int DEG_2 = 15;
+ static const int SEP_2 = 1;
+
+ static const int TYPE_3 = 3; // x**31 + x**3 + 1
+ static const int BREAK_3 = 128;
+ static const int DEG_3 = 31;
+ static const int SEP_3 = 3;
+
+ static const int TYPE_4 = 4; // x**63 + x + 1
+ static const int BREAK_4 = 256;
+ static const int DEG_4 = 63;
+ static const int SEP_4 = 1;
+
+ static const int MAX_TYPES = 5; // Max number of types above
+
+ bool initialized;
+ long degrees[MAX_TYPES];
+ long seps [MAX_TYPES];
+ long randtbl[DEG_3 + 1];
+
+ long *fptr;
+ long *rptr;
+
+ long *state;
+ long rand_type;
+ long rand_deg;
+ long rand_sep;
+ long *end_ptr;
+
+public:
+ RandomGenerator();
+ ~RandomGenerator();
+
+// Documentation of user-visible calls:
+
+ // Initialize the RNG with a 31-bit seed
+ // if x is zero or absent, calls to time() will get a time-randomized seed
+ // the value returned is the value of the seed used.
+ int srand(int x=0);
+
+ // generate random 31-bit numbers
+ // calls to the following return a value evenly distributed between u (or
+ // 0 if not specified) and v (or RAND_MAX if not specified). Return
+ // values may include u, but never v.
+ int rand();
+ int rand(int v);
+ int rand(int u, int v);
+ double randf(double v);
+ double randf(double u, double v);
+
+ // For Squirrel wrapper, since miniswig (and even squirrel?) doesn't
+ // support function overloading or doubles
+ int rand1i(int v) { return rand(v); }
+ int rand2i(int u, int v) { return rand(u, v); }
+ float rand1f(float v)
+ { return static_cast<float>(randf(static_cast<double>(v))); }
+ float rand2f(float u, float v)
+ { return static_cast<float>(randf(static_cast<double>(u),
+ static_cast<double>(v))); }
+
+//private:
+ void initialize();
+ void srandom(unsigned long x);
+// void srandomdev();
+// char *initstate(unsigned long seed, char *arg_state, long n);
+// char *setstate(char *arg_state);
+ long random();
+};
+
+extern RandomGenerator systemRandom;
+
+#endif //__RANDOM_GENERATOR__
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#ifndef __PLAYER_H__
-#define __PLAYER_H__
+#ifndef __SCRIPTING_PLAYER_H__
+#define __SCRIPTING_PLAYER_H__
namespace Scripting
{
--- /dev/null
+// $Id: player.hpp 3350 2006-04-16 14:43:57Z sommer $
+//
+// SuperTux
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef __SCRIPTING_RANDOM_GENERATOR_H__
+#define __SCRIPTING_RANDOM_GENERATOR_H__
+
+namespace Scripting
+{
+
+class RandomGenerator
+{
+public:
+#ifndef SCRIPTING_API
+ virtual ~RandomGenerator()
+ {}
+#endif
+
+ /**
+ * Seed random number generator
+ */
+ virtual int srand(int x) = 0;
+ /**
+ * Return random number in range [0, RAND_MAX)
+ */
+ virtual int rand() = 0;
+ /**
+ * Return random number in range [0, v)
+ */
+ virtual int rand1i(int v) = 0;
+ /**
+ * Return random number in range [u, v)
+ */
+ virtual int rand2i(int u, int v) = 0;
+ /**
+ * Return random number in range [0, v)
+ */
+ virtual float rand1f(float v) = 0;
+ /**
+ * Return random number in range [u, v)
+ */
+ virtual float rand2f(float u, float v) = 0;
+};
+
+}
+
+#endif
+
#include "log.hpp"
#include "level.hpp"
#include "physfs/physfs_stream.hpp"
+#include "../random_generator.hpp"
#ifdef ENABLE_SQDBG
#include <sqdbg/sqrdbg.h>
// TODO remove this at some point... it shoud just be functions not an object
expose_object(global_vm, -1, new Scripting::Level(), "Level", true);
+ expose_object(global_vm, -1, &systemRandom, "RandomGenerator", false);
sq_pop(global_vm, 1);
}
+static int RandomGenerator_release_hook(SQUserPointer ptr, int )
+{
+ Scripting::RandomGenerator* _this = reinterpret_cast<Scripting::RandomGenerator*> (ptr);
+ delete _this;
+ return 0;
+}
+
+static int RandomGenerator_srand_wrapper(HSQUIRRELVM vm)
+{
+ Scripting::RandomGenerator* _this;
+ if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
+ sq_throwerror(vm, _SC("'srand' called without instance"));
+ return SQ_ERROR;
+ }
+ int arg0;
+ if(SQ_FAILED(sq_getinteger(vm, 2, &arg0))) {
+ sq_throwerror(vm, _SC("Argument 1 not an integer"));
+ return SQ_ERROR;
+ }
+
+ try {
+ int return_value = _this->srand(arg0);
+
+ sq_pushinteger(vm, return_value);
+ return 1;
+
+ } catch(std::exception& e) {
+ sq_throwerror(vm, e.what());
+ return SQ_ERROR;
+ } catch(...) {
+ sq_throwerror(vm, _SC("Unexpected exception while executing function 'srand'"));
+ return SQ_ERROR;
+ }
+
+}
+
+static int RandomGenerator_rand_wrapper(HSQUIRRELVM vm)
+{
+ Scripting::RandomGenerator* _this;
+ if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
+ sq_throwerror(vm, _SC("'rand' called without instance"));
+ return SQ_ERROR;
+ }
+
+ try {
+ int return_value = _this->rand();
+
+ sq_pushinteger(vm, return_value);
+ return 1;
+
+ } catch(std::exception& e) {
+ sq_throwerror(vm, e.what());
+ return SQ_ERROR;
+ } catch(...) {
+ sq_throwerror(vm, _SC("Unexpected exception while executing function 'rand'"));
+ return SQ_ERROR;
+ }
+
+}
+
+static int RandomGenerator_rand1i_wrapper(HSQUIRRELVM vm)
+{
+ Scripting::RandomGenerator* _this;
+ if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
+ sq_throwerror(vm, _SC("'rand1i' called without instance"));
+ return SQ_ERROR;
+ }
+ int arg0;
+ if(SQ_FAILED(sq_getinteger(vm, 2, &arg0))) {
+ sq_throwerror(vm, _SC("Argument 1 not an integer"));
+ return SQ_ERROR;
+ }
+
+ try {
+ int return_value = _this->rand1i(arg0);
+
+ sq_pushinteger(vm, return_value);
+ return 1;
+
+ } catch(std::exception& e) {
+ sq_throwerror(vm, e.what());
+ return SQ_ERROR;
+ } catch(...) {
+ sq_throwerror(vm, _SC("Unexpected exception while executing function 'rand1i'"));
+ return SQ_ERROR;
+ }
+
+}
+
+static int RandomGenerator_rand2i_wrapper(HSQUIRRELVM vm)
+{
+ Scripting::RandomGenerator* _this;
+ if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
+ sq_throwerror(vm, _SC("'rand2i' called without instance"));
+ return SQ_ERROR;
+ }
+ int arg0;
+ if(SQ_FAILED(sq_getinteger(vm, 2, &arg0))) {
+ sq_throwerror(vm, _SC("Argument 1 not an integer"));
+ return SQ_ERROR;
+ }
+ int arg1;
+ if(SQ_FAILED(sq_getinteger(vm, 3, &arg1))) {
+ sq_throwerror(vm, _SC("Argument 2 not an integer"));
+ return SQ_ERROR;
+ }
+
+ try {
+ int return_value = _this->rand2i(arg0, arg1);
+
+ sq_pushinteger(vm, return_value);
+ return 1;
+
+ } catch(std::exception& e) {
+ sq_throwerror(vm, e.what());
+ return SQ_ERROR;
+ } catch(...) {
+ sq_throwerror(vm, _SC("Unexpected exception while executing function 'rand2i'"));
+ return SQ_ERROR;
+ }
+
+}
+
+static int RandomGenerator_rand1f_wrapper(HSQUIRRELVM vm)
+{
+ Scripting::RandomGenerator* _this;
+ if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
+ sq_throwerror(vm, _SC("'rand1f' called without instance"));
+ return SQ_ERROR;
+ }
+ float arg0;
+ if(SQ_FAILED(sq_getfloat(vm, 2, &arg0))) {
+ sq_throwerror(vm, _SC("Argument 1 not a float"));
+ return SQ_ERROR;
+ }
+
+ try {
+ float return_value = _this->rand1f(arg0);
+
+ sq_pushfloat(vm, return_value);
+ return 1;
+
+ } catch(std::exception& e) {
+ sq_throwerror(vm, e.what());
+ return SQ_ERROR;
+ } catch(...) {
+ sq_throwerror(vm, _SC("Unexpected exception while executing function 'rand1f'"));
+ return SQ_ERROR;
+ }
+
+}
+
+static int RandomGenerator_rand2f_wrapper(HSQUIRRELVM vm)
+{
+ Scripting::RandomGenerator* _this;
+ if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
+ sq_throwerror(vm, _SC("'rand2f' called without instance"));
+ return SQ_ERROR;
+ }
+ float arg0;
+ if(SQ_FAILED(sq_getfloat(vm, 2, &arg0))) {
+ sq_throwerror(vm, _SC("Argument 1 not a float"));
+ return SQ_ERROR;
+ }
+ float arg1;
+ if(SQ_FAILED(sq_getfloat(vm, 3, &arg1))) {
+ sq_throwerror(vm, _SC("Argument 2 not a float"));
+ return SQ_ERROR;
+ }
+
+ try {
+ float return_value = _this->rand2f(arg0, arg1);
+
+ sq_pushfloat(vm, return_value);
+ return 1;
+
+ } catch(std::exception& e) {
+ sq_throwerror(vm, e.what());
+ return SQ_ERROR;
+ } catch(...) {
+ sq_throwerror(vm, _SC("Unexpected exception while executing function 'rand2f'"));
+ return SQ_ERROR;
+ }
+
+}
+
static int display_wrapper(HSQUIRRELVM vm)
{
return Scripting::display(vm);
sq_remove(v, -2); // remove root table
}
+void create_squirrel_instance(HSQUIRRELVM v, Scripting::RandomGenerator* object, bool setup_releasehook)
+{
+ using namespace Wrapper;
+
+ sq_pushroottable(v);
+ sq_pushstring(v, "RandomGenerator", -1);
+ if(SQ_FAILED(sq_get(v, -2))) {
+ std::ostringstream msg;
+ msg << "Couldn't resolved squirrel type 'RandomGenerator'";
+ throw SquirrelError(v, msg.str());
+ }
+
+ if(SQ_FAILED(sq_createinstance(v, -1)) || SQ_FAILED(sq_setinstanceup(v, -1, object))) {
+ std::ostringstream msg;
+ msg << "Couldn't setup squirrel instance for object of type 'RandomGenerator'";
+ throw SquirrelError(v, msg.str());
+ }
+ sq_remove(v, -2); // remove object name
+
+ if(setup_releasehook) {
+ sq_setreleasehook(v, -1, RandomGenerator_release_hook);
+ }
+
+ sq_remove(v, -2); // remove root table
+}
+
void register_supertux_wrapper(HSQUIRRELVM v)
{
using namespace Wrapper;
throw SquirrelError(v, "Couldn't register class 'FloatingImage'");
}
+ // Register class RandomGenerator
+ sq_pushstring(v, "RandomGenerator", -1);
+ if(sq_newclass(v, SQFalse) < 0) {
+ std::ostringstream msg;
+ msg << "Couldn't create new class 'RandomGenerator'";
+ throw SquirrelError(v, msg.str());
+ }
+ sq_pushstring(v, "srand", -1);
+ sq_newclosure(v, &RandomGenerator_srand_wrapper, 0);
+ if(SQ_FAILED(sq_createslot(v, -3))) {
+ throw SquirrelError(v, "Couldn't register function 'srand'");
+ }
+
+ sq_pushstring(v, "rand", -1);
+ sq_newclosure(v, &RandomGenerator_rand_wrapper, 0);
+ if(SQ_FAILED(sq_createslot(v, -3))) {
+ throw SquirrelError(v, "Couldn't register function 'rand'");
+ }
+
+ sq_pushstring(v, "rand1i", -1);
+ sq_newclosure(v, &RandomGenerator_rand1i_wrapper, 0);
+ if(SQ_FAILED(sq_createslot(v, -3))) {
+ throw SquirrelError(v, "Couldn't register function 'rand1i'");
+ }
+
+ sq_pushstring(v, "rand2i", -1);
+ sq_newclosure(v, &RandomGenerator_rand2i_wrapper, 0);
+ if(SQ_FAILED(sq_createslot(v, -3))) {
+ throw SquirrelError(v, "Couldn't register function 'rand2i'");
+ }
+
+ sq_pushstring(v, "rand1f", -1);
+ sq_newclosure(v, &RandomGenerator_rand1f_wrapper, 0);
+ if(SQ_FAILED(sq_createslot(v, -3))) {
+ throw SquirrelError(v, "Couldn't register function 'rand1f'");
+ }
+
+ sq_pushstring(v, "rand2f", -1);
+ sq_newclosure(v, &RandomGenerator_rand2f_wrapper, 0);
+ if(SQ_FAILED(sq_createslot(v, -3))) {
+ throw SquirrelError(v, "Couldn't register function 'rand2f'");
+ }
+
+ if(SQ_FAILED(sq_createslot(v, -3))) {
+ throw SquirrelError(v, "Couldn't register class 'RandomGenerator'");
+ }
+
}
} // end of namespace Scripting
void create_squirrel_instance(HSQUIRRELVM v, Scripting::Text* object, bool setup_releasehook = false);
void create_squirrel_instance(HSQUIRRELVM v, Scripting::Player* object, bool setup_releasehook = false);
void create_squirrel_instance(HSQUIRRELVM v, Scripting::FloatingImage* object, bool setup_releasehook = false);
+void create_squirrel_instance(HSQUIRRELVM v, Scripting::RandomGenerator* object, bool setup_releasehook = false);
}
#include "player.hpp"
#include "floating_image.hpp"
#include "anchor_points.hpp"
-
+#include "random_generator.hpp"
#include "log.hpp"
#include "options_menu.hpp"
#include "console.hpp"
+#include "random_generator.hpp"
enum MainMenuIDs {
MNID_STARTGAME,
if(pathBlocked)
jumpDuration = 0.5;
else
- jumpDuration = float(rand() % 500 + 300) / 1000.0;
+ jumpDuration = systemRandom.randf(0.3, 0.8);
jumpPushTimer.start(jumpDuration);
- randomWaitTimer.start(float(rand() % 3000 + 3000) / 1000.0);
+ randomWaitTimer.start(systemRandom.randf(3.0, 6.0));
}
// Keep jump button pressed