1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-28 08:37:12 +00:00

Update to latest Monster, and minor simplification of the scripts.

git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@83 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
nkorslund 2009-01-22 20:36:36 +00:00
parent 656007cf01
commit 6dcf6c565a
25 changed files with 187 additions and 276 deletions

View File

@ -31,7 +31,6 @@ import std.path;
import monster.util.aa; import monster.util.aa;
import monster.util.string; import monster.util.string;
import util.random;
import bsa.bsafile; import bsa.bsafile;
@ -51,9 +50,6 @@ import nif.nif;
import core.filefinder; import core.filefinder;
//import core.config; //import core.config;
// Random number generator
DRand rnd;
// These are handles for various resources. They may refer to a file // These are handles for various resources. They may refer to a file
// in the file system, an entry in a BSA archive, or point to an // in the file system, an entry in a BSA archive, or point to an
// already loaded resource. Resource handles that are not implemented // already loaded resource. Resource handles that are not implemented
@ -129,8 +125,6 @@ struct ResourceManager
void initResources() void initResources()
{ {
rnd = new DRand;
bsa = new FileFinder(config.bsaDir, "bsa", Recurse.No); bsa = new FileFinder(config.bsaDir, "bsa", Recurse.No);
archives.length = bsa.length; archives.length = bsa.length;
foreach(int i, ref BSAFile f; archives) foreach(int i, ref BSAFile f; archives)

View File

@ -25,7 +25,7 @@ module esm.loadlevlist;
import esm.imports; import esm.imports;
import esm.loadcrea; import esm.loadcrea;
import util.random; import monster.modules.random : randInt;
/* /*
* Leveled lists. Since these have identical layout, I only bothered * Leveled lists. Since these have identical layout, I only bothered
@ -103,7 +103,7 @@ struct LeveledListT(bool creature)
// TODO: Find out if this is indeed correct. // TODO: Find out if this is indeed correct.
// Test if no creature is to be selected // Test if no creature is to be selected
if(rnd.randInt(0, 255) < chanceNone) return -1; if(randInt(0, 255) < chanceNone) return -1;
// Find the highest item below or equal to the Player level // Find the highest item below or equal to the Player level
for(i=list.length-1; i>=0; i--) for(i=list.length-1; i>=0; i--)
@ -126,7 +126,7 @@ struct LeveledListT(bool creature)
} }
// Select a random item // Select a random item
return rnd.randInt(bottom, top); return randInt(bottom, top);
} }
void load() void load()

View File

@ -28,7 +28,7 @@ import std.stdio;
import core.memory; import core.memory;
import esm.esmmain; import esm.esmmain;
import monster.util.string; import monster.util.string;
import mscripts.object; import mscripts.setup;
import std.gc; import std.gc;
import gcstats; import gcstats;

View File

@ -274,6 +274,8 @@ struct Function
auto fd = new FuncDeclaration; auto fd = new FuncDeclaration;
// Parse and comile the function // Parse and comile the function
fd.parseFile(tokens, this); fd.parseFile(tokens, this);
name.str = file;
name.loc.fname = file;
fd.resolve(mc.sc); fd.resolve(mc.sc);
fd.resolveBody(); fd.resolveBody();
fd.compile(); fd.compile();
@ -287,7 +289,7 @@ struct Function
private: private:
static const char[] int_class = "class _Func_Internal_;"; static const char[] int_class = "class _ScriptFile_;";
static MonsterClass int_mc; static MonsterClass int_mc;
static MonsterObject *int_mo; static MonsterObject *int_mo;
} }

View File

@ -338,6 +338,13 @@ abstract class Scope
void registerImport(MonsterClass mc) void registerImport(MonsterClass mc)
{ registerImport(new ImportHolder(mc)); } { registerImport(new ImportHolder(mc)); }
// Even more user-friendly version. Takes a list of class names.
void registerImport(char[][] cls ...)
{
foreach(c; cls)
registerImport(MonsterClass.find(c));
}
// Used for summing up stack level. Redeclared in StackScope. // Used for summing up stack level. Redeclared in StackScope.
int getTotLocals() { return 0; } int getTotLocals() { return 0; }
int getLocals() { assert(0); } int getLocals() { assert(0); }

View File

@ -3,6 +3,7 @@ module monster.modules.all;
import monster.modules.io; import monster.modules.io;
import monster.modules.timer; import monster.modules.timer;
import monster.modules.frames; import monster.modules.frames;
import monster.modules.random;
import monster.modules.threads; import monster.modules.threads;
void initAllModules() void initAllModules()
@ -10,5 +11,6 @@ void initAllModules()
initIOModule(); initIOModule();
initTimerModule(); initTimerModule();
initFramesModule(); initFramesModule();
initThreadModule; initThreadModule();
initRandomModule();
} }

49
monster/modules/random.d Normal file
View File

@ -0,0 +1,49 @@
// This module provides simple random number generation. Since this is
// intended for game development, speed and simplicity is favored over
// flexibility and random number quality.
module monster.modules.random;
import monster.monster;
import std.random;
const char[] moduleDef =
"module random;
native uint rand(); // Return a number between 0 and uint.max, inclusive
native float frand(); // Return a number between 0 and 1, inclusive
// Return a random number between a and b, inclusive. Allows negative
// numbers, and works with a>b, a<b and a==b
native int randInt(int a, int b);
"; //"
const float _frandFactor = 1.0/uint.max;
// Return a random integer between a and b, inclusive.
int randInt(int a, int b)
out(result)
{
// Result must be in range m <= result <= M, where m=min(a,b) and M=max(a,b)
if(b >= a) assert( (a <= result) && (result <= b) );
else if(a > b) assert( (b <= result) && (result <= a) );
}
body
{
if(a>b) return cast(int)(rand() % (a-b+1)) + b;
else if(b>a) return cast(int)(rand() % (b-a+1)) + a;
else return a;
}
void initRandomModule()
{
static MonsterClass mc;
if(mc !is null) return;
mc = new MonsterClass(MC.String, moduleDef, "random");
mc.bind("rand", { stack.pushInt(rand()); });
mc.bind("frand", { stack.pushFloat(rand()*_frandFactor); });
mc.bind("randInt", { stack.pushInt(randInt(stack.popInt,
stack.popInt)); });
}

View File

@ -0,0 +1,8 @@
module random;
native uint rand(); // Return a number between 0 and uint.max, inclusive
native float frand(); // Return a number between 0 and 1, inclusive
// Return a random number between a and b, inclusive. Allows negative
// numbers, and works with a>b, a<b and a==b
native int randInt(int a, int b);

View File

@ -28,20 +28,12 @@ native restart();
// Call a (paused) thread directly - returns when the thread exits or // Call a (paused) thread directly - returns when the thread exits or
// calls an idle function. // calls an idle function.
idle resume(); idle call();
// Wait for a thread to finish. Will not return until the thread is // Wait for a thread to finish. Will not return until the thread is
// dead. // dead.
idle wait(); idle wait();
// Call a function as a thread
thread call(char[] name)
{
var t = create(name);
t.resume();
return t;
}
// Start a function as a thread in the background // Start a function as a thread in the background
thread start(char[] name) thread start(char[] name)
{ {
@ -51,6 +43,18 @@ thread start(char[] name)
} }
"; //" "; //"
/*
The char[] name stuff above will of course be replaced with real
function pointers once those are done. We will also add:
function() wrap(function f())
{
var t = create(f);
return {{ t.call(); }
}
*/
MonsterObject *trdSing; MonsterObject *trdSing;
class Kill : IdleFunction class Kill : IdleFunction
@ -134,49 +138,34 @@ void create()
nd = cthread.fstack.list.getNext(nd); nd = cthread.fstack.list.getNext(nd);
auto mo = nd.obj; auto mo = nd.obj;
// Find the function auto trd = mo.thread(name);
auto fn = mo.cls.findFunction(name);
if(fn.paramSize > 0)
fail("create(): function " ~ name ~ " cannot have parameters");
// Create a new thread
Thread *trd = Thread.getNew();
// Schedule the thread run the next frame
trd.pushFunc(fn, mo);
assert(trd.isPaused);
// This will mess with the stack frame though, so set it up
// correctly.
trd.fstack.cur.frame = stack.getStartInt(0);
cthread.fstack.restoreFrame();
stack.pushObject(createObj(trd)); stack.pushObject(createObj(trd));
} }
// Resume is used to restore a thread that was previously paused. It // Call is used to restore a thread that was previously paused. It
// will enter the thread immediately, like call. If you wish to run it // will enter the thread immediately, like a normal function call, but
// later, use restart instead. // it will still run in its own thread. If you only wish to schedule
class Resume : IdleFunction // it for later, use restart instead.
class Call : IdleFunction
{ {
override: override:
IS initiate(Thread *t) IS initiate(Thread *t)
{ {
if(params.obj is trdSing) if(params.obj is trdSing)
fail("Cannot use resume() on our own thread."); fail("Cannot use call() on our own thread.");
// Get the thread we're resuming // Get the thread we're resuming
auto trd = getOwner(); auto trd = getOwner();
if(trd is t) if(trd is t)
fail("Cannot use resume() on our own thread."); fail("Cannot use call() on our own thread.");
if(trd.isDead) if(trd.isDead)
fail("Cannot resume a dead thread."); fail("Cannot call a dead thread.");
if(!trd.isPaused) if(!trd.isPaused)
fail("Can only use resume() on paused threads"); fail("Can only use call() on paused threads");
// Background the current thread. Move it to the pause list // Background the current thread. Move it to the pause list
// first, so background doesn't inadvertently delete it. // first, so background doesn't inadvertently delete it.
@ -234,18 +223,7 @@ class Wait : IdleFunction
} }
void restart() void restart()
{ { getOwner().restart(); }
auto trd = getOwner();
if(trd.isDead)
fail("Cannot restart a dead thread");
if(!trd.isPaused)
fail("Can only use restart() on paused threads");
// Move to the runlist
trd.moveTo(scheduler.runNext);
}
void isDead() void isDead()
{ stack.pushBool(getOwner().isDead); } { stack.pushBool(getOwner().isDead); }
@ -270,7 +248,7 @@ void initThreadModule()
trdSing = _threadClass.getSing(); trdSing = _threadClass.getSing();
_threadClass.bind("kill", new Kill); _threadClass.bind("kill", new Kill);
_threadClass.bind("resume", new Resume); _threadClass.bind("call", new Call);
_threadClass.bind("pause", new Pause); _threadClass.bind("pause", new Pause);
_threadClass.bind("wait", new Wait); _threadClass.bind("wait", new Wait);

View File

@ -175,8 +175,6 @@ struct BufferList(int size)
void free(void* p) { remove(cast(ValuePtr)p); } void free(void* p) { remove(cast(ValuePtr)p); }
} }
import std.stdio;
struct Buffers struct Buffers
{ {
static: static:
@ -204,8 +202,7 @@ struct Buffers
// Too large for our lists - just use malloc // Too large for our lists - just use malloc
else else
{ {
writefln("WARNING: using malloc for %s ints (%s bytes)", //writefln("WARNING: using malloc for %s ints (%s bytes)", size, size*int.sizeof);
size, size*int.sizeof);
return ( cast(int*)malloc(size*int.sizeof) )[0..size]; return ( cast(int*)malloc(size*int.sizeof) )[0..size];
} }
} }

View File

@ -131,7 +131,9 @@ struct StackPoint
name = func.name.str; name = func.name.str;
if(isIdle) type = "idle"; if(isIdle) type = "idle";
else type = "function"; else if(isNormal) type = "script";
else if(isNative) type = "native";
else assert(0);
} }
// Function location and name // Function location and name
@ -322,8 +324,17 @@ struct FunctionStack
{ {
char[] res; char[] res;
int i;
foreach(ref c; list) foreach(ref c; list)
res = c.toString ~ '\n' ~ res; {
char[] msg;
if(i == 0)
msg = " (<---- current function)";
else if(i == list.length-1)
msg = " (<---- start of function stack)";
res = c.toString ~ msg ~ '\n' ~ res;
i++;
}
return "Trace:\n" ~ res; return "Trace:\n" ~ res;
} }

View File

@ -27,6 +27,7 @@ import monster.vm.thread;
import monster.vm.error; import monster.vm.error;
import monster.vm.mclass; import monster.vm.mclass;
import monster.vm.arrays; import monster.vm.arrays;
import monster.vm.stack;
import monster.util.freelist; import monster.util.freelist;
import monster.util.list; import monster.util.list;
@ -34,6 +35,7 @@ import monster.util.list;
import monster.compiler.states; import monster.compiler.states;
import monster.compiler.variables; import monster.compiler.variables;
import monster.compiler.scopes; import monster.compiler.scopes;
import monster.compiler.functions;
import std.string; import std.string;
import std.stdio; import std.stdio;
@ -262,6 +264,44 @@ struct MonsterObject
cls.findFunction(name).call(this); cls.findFunction(name).call(this);
} }
// Create a paused thread that's set up to call the given
// function. It must be started with Thread.call() or
// Thread.restart().
Thread *thread(char[] name)
{ return thread(cls.findFunction(name)); }
Thread *thread(Function *fn)
{
assert(fn !is null);
if(fn.paramSize > 0)
fail("thread(): function " ~ fn.name.str ~ " cannot have parameters");
Thread *trd = Thread.getNew();
// Schedule the function to run the next frame
trd.pushFunc(fn, this);
assert(trd.isPaused);
assert(trd.fstack.cur !is null);
// pushFunc will mess with the stack frame though, so fix it.
trd.fstack.cur.frame = stack.getStart();
if(cthread !is null)
cthread.fstack.restoreFrame();
return trd;
}
// Create a thread containing the function and schedule it to start
// the next frame
Thread *start(char[] name)
{ return start(cls.findFunction(name)); }
Thread *start(Function *fn)
{
assert(fn !is null);
auto trd = thread(fn);
trd.restart();
return trd;
}
// Call a function non-virtually. In other words, ignore // Call a function non-virtually. In other words, ignore
// derived objects. // derived objects.
void nvcall(char[] name) void nvcall(char[] name)

View File

@ -139,12 +139,9 @@ struct CodeStack
} }
// Get the pointer from the start of the stack // Get the pointer from the start of the stack
int *getStartInt(int pos) int *getStart()
{ {
if(pos < 0 || pos >= getPos) return cast(int*)data.ptr;
fail("CodeStack.getStartInt() pointer out of range");
return &data[pos];
} }
// Get the pointer to an int at the given position backwards from // Get the pointer to an int at the given position backwards from

View File

@ -124,6 +124,20 @@ struct Thread
return cn; return cn;
} }
// Schedule the function to run the next frame. Can only be used on
// paused threads.
void restart()
{
if(isDead)
fail("Cannot restart a dead thread");
if(!isPaused)
fail("Can only use restart() on paused threads");
// Move to the runlist
moveTo(scheduler.runNext);
}
// Stop the thread and return it to the freelist // Stop the thread and return it to the freelist
void kill() void kill()
{ {
@ -238,6 +252,7 @@ struct Thread
bool isTransient() { return list is &scheduler.transient; } bool isTransient() { return list is &scheduler.transient; }
bool isRunning() { return cthread is this; } bool isRunning() { return cthread is this; }
bool isDead() { return list is null; } bool isDead() { return list is null; }
bool isAlive() { return !isDead; }
bool isPaused() { return list is &scheduler.paused; } bool isPaused() { return list is &scheduler.paused; }
// Get the next node in the freelist // Get the next node in the freelist
@ -293,6 +308,7 @@ struct Thread
// Background the thread // Background the thread
background(); background();
assert(cthread is null);
} }
// Put this thread in the background. Acquires the stack and // Put this thread in the background. Acquires the stack and
@ -401,6 +417,8 @@ struct Thread
if(fstack.cur !is null) if(fstack.cur !is null)
fl = fstack.cur.getFloc(); fl = fstack.cur.getFloc();
msg ~= '\n' ~ fstack.toString();
.fail(msg, fl); .fail(msg, fl);
} }

View File

@ -21,7 +21,7 @@
*/ */
singleton Config : Object; singleton Config;
// Only some config options have been moved into Monster. Key bindings // Only some config options have been moved into Monster. Key bindings
// and other low-level settings are still handled in D. // and other low-level settings are still handled in D.

View File

@ -1,12 +1,14 @@
// Small script that prints the FPS to screen with regular intervals. // Small script that prints the FPS to screen with regular intervals.
import io, timer, frames; import frames;
// Sleep one frame. This makes sure that we won't start running until // Sleep one frame. This makes sure that we won't start running until
// the rendering begins. Not critically important, but it prevents the // the rendering begins. Not critically important, but it prevents the
// first printed value from being 'nan'. // first printed value from being 'nan'.
fsleep(1); fsleep(1);
// counter and totalTime (in the 'frames' module) are updated
// automatically by the system.
ulong lastFrame = counter; ulong lastFrame = counter;
float lastTime = totalTime; float lastTime = totalTime;

View File

@ -23,7 +23,7 @@
// An object that exists inside a cell. All cell objects must have a // An object that exists inside a cell. All cell objects must have a
// position in space. // position in space.
class GameObject : Object; class GameObject;
// Is this object placed in a cell? isPlaced is true if the object is // Is this object placed in a cell? isPlaced is true if the object is
// displayed inside a cell with a mesh and given 3D coordinates, and // displayed inside a cell with a mesh and given 3D coordinates, and

View File

@ -24,7 +24,7 @@
// Contains all the game settings (GMST) variables of Morrowind, // Contains all the game settings (GMST) variables of Morrowind,
// Tribunal and Bloodmoon. Based on "Morrowind Scripting for Dummies" // Tribunal and Bloodmoon. Based on "Morrowind Scripting for Dummies"
// (v9). // (v9).
singleton GMST : Object; singleton GMST;
// Most of the comments are copied from MSfD. A bit of cleanup is // Most of the comments are copied from MSfD. A bit of cleanup is
// still needed. // still needed.

View File

@ -1,30 +0,0 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (object.mn) is part of the OpenMW package.
OpenMW is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
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
version 3 along with this program. If not, see
http://www.gnu.org/licenses/ .
*/
// This is the base class of all OpenMW Monster classes.
class Object;
import io, timer;
// Get a random number between a and b (inclusive)
native int randInt(int a, int b);

View File

@ -21,16 +21,13 @@
*/ */
module mscripts.object; module mscripts.setup;
import monster.monster; import monster.monster;
import monster.compiler.scopes : global;
import monster.modules.timer; import monster.modules.timer;
import std.stdio;
import std.date;
import core.resource : rnd;
import core.config; import core.config;
import sound.music;
// Set up the base Monster classes we need in OpenMW // Set up the base Monster classes we need in OpenMW
void initMonsterScripts() void initMonsterScripts()
@ -43,17 +40,13 @@ void initMonsterScripts()
vm.addPath("mscripts/gameobjects/"); vm.addPath("mscripts/gameobjects/");
vm.addPath("mscripts/sound/"); vm.addPath("mscripts/sound/");
// Make sure the Object class is loaded // Import some modules into the global scope, so we won't have to
auto mc = new MonsterClass("Object", "object.mn"); // import them manually in each script.
global.registerImport("io", "random", "timer");
// Get the Config singleton object // Get the Config singleton object
config.mo = (new MonsterClass("Config")).getSing(); config.mo = (new MonsterClass("Config")).getSing();
// Bind various functions
mc.bind("randInt",
{ stack.pushInt(rnd.randInt
(stack.popInt,stack.popInt));});
// Run the fps ticker // Run the fps ticker
vm.run("fpsticker.mn"); vm.run("fpsticker.mn");

View File

@ -26,7 +26,7 @@
fade in and fade out, and adjust volume. fade in and fade out, and adjust volume.
*/ */
class Jukebox : Object; class Jukebox;
// Between 0 (off) and 1 (full volume) // Between 0 (off) and 1 (full volume)
float fadeLevel = 0.0; float fadeLevel = 0.0;

View File

@ -22,7 +22,7 @@
*/ */
// This class controls all the music. // This class controls all the music.
singleton Music : Object; singleton Music;
// Create one jukebox for normal music, and one for battle music. This // Create one jukebox for normal music, and one for battle music. This
// way we can pause / fade out one while the other resumes / fades in. // way we can pause / fade out one while the other resumes / fades in.

View File

@ -1,7 +1,5 @@
// A short example script // A short example script
import io, timer;
sleep(6); sleep(6);
while(true) while(true)

View File

@ -43,7 +43,7 @@ import core.config;
import monster.util.string; import monster.util.string;
import monster.vm.mclass; import monster.vm.mclass;
import mscripts.object; import mscripts.setup;
import sound.audio; import sound.audio;

View File

@ -1,155 +0,0 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (random.d) is part of the OpenMW package.
OpenMW is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
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
version 3 along with this program. If not, see
http://www.gnu.org/licenses/ .
*/
module util.random;
private import std.date;
private import std.random;
abstract class Random
{
static const double scale = 1.0/uint.max;
// Initialize from current time
this() { initialize(); }
// Initialize from parameter
this(long seed) { initialize(seed); }
// Reinitialize with seed
abstract void initialize(long newSeed);
// Produce random numbers between 0 and uint.max
abstract uint rand();
// Default is to initialize using current time as seed
void initialize() { initialize(getUTCtime()); }
// Produce a uniform random number between 0 and 1
double random()
{
return rand() * scale;
}
// Return a uniform random number between a and b. Works for the
// both the cases a < b and a > b.
double random(double a, double b)
in
{
// We only disallow nan parameters
assert(a <>= b);
}
out(result)
{
// Result must be in range m < result < M, where m=min(a,b) and M=max(a,b)
if(b > a) assert( (a < result) && (result < b) );
else if(a > b) assert( (b < result) && (result < a) );
}
body
{ return random()*(b - a) + a; }
// Return a random integer between a and b, inclusive.
int randInt(int a, int b)
out(result)
{
// Result must be in range m <= result <= M, where m=min(a,b) and M=max(a,b)
if(b >= a) assert( (a <= result) && (result <= b) );
else if(a > b) assert( (b <= result) && (result <= a) );
}
body
{
if(a>b) return cast(int)(rand() % (a-b+1)) + b;
else if(b>a) return cast(int)(rand() % (b-a+1)) + a;
else return a;
}
// Allow using "function call" syntax:
//
// Random ran = new Random1;
// double d = ran(); // Calls ran.random()
// d = ran(a,b); // Calls ran.random(a,b);
double opCall() { return random(); }
double opCall(double a, double b) { return random(a, b); }
// Return the seed originally given the object
long getSeed() {return origSeed;}
protected:
long origSeed; // Value used to seed the generator
}
// Uses the standard library generator
class DRand : Random
{
// Initialize from current time
this() { super(); }
// Initialize from parameter
this(long seed) { super(seed); }
uint rand() { return std.random.rand(); }
void initialize(long newSeed)
{
origSeed = newSeed;
rand_seed(cast(uint)newSeed, 0);
}
alias Random.initialize initialize;
unittest
{
struct tmp { import std.stdio; }
alias tmp.writef writef;
alias tmp.writefln writefln;
writefln("Unittest for class DRand");
DRand ran = new DRand;
writefln("Seed (from time) = ", ran.getSeed());
// Take a look at some numbers on screen
writefln("Some random numbers in [0,1]:");
for(int i=0; i<10; i++)
writef(" ", ran());
ran = new DRand(0);
writefln("\nNew seed (preset) = ", ran.getSeed());
// Take a look at some numbers on screen
writefln("Some random numbers in [0,1]:");
for(int i=0; i<10; i++)
writef(" ", ran());
// Check that all interfaces work (compile time)
ran();
ran(1,2);
ran.random();
ran.random(3,4);
ran.initialize();
ran.initialize(10);
ran.randInt(-3,5);
writefln("\nEnd of unittest for class DRand\n");
}
}