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:
parent
656007cf01
commit
6dcf6c565a
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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); }
|
||||||
|
@ -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
49
monster/modules/random.d
Normal 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)); });
|
||||||
|
}
|
8
monster/modules/random.mn
Normal file
8
monster/modules/random.mn
Normal 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);
|
@ -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);
|
||||||
|
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
|
@ -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");
|
||||||
|
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
// A short example script
|
// A short example script
|
||||||
|
|
||||||
import io, timer;
|
|
||||||
|
|
||||||
sleep(6);
|
sleep(6);
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
|
2
openmw.d
2
openmw.d
@ -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;
|
||||||
|
|
||||||
|
155
util/random.d
155
util/random.d
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user