From 7349221b9ca272500adc29486d41f94c11e329c2 Mon Sep 17 00:00:00 2001 From: nkorslund Date: Fri, 7 Nov 2008 13:14:46 +0000 Subject: [PATCH] Made the first working Monster script within OpenMW git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@62 ea6a568a-9f4f-0410-981a-c910a81bb256 --- input/events.d | 5 ++ monster/compiler/assembler.d | 4 +- monster/compiler/expression.d | 6 +- monster/compiler/functions.d | 2 +- monster/compiler/operators.d | 2 +- monster/compiler/properties.d | 2 +- monster/compiler/scopes.d | 4 +- monster/compiler/statement.d | 4 +- monster/compiler/states.d | 2 +- monster/compiler/tokenizer.d | 6 +- monster/compiler/types.d | 4 +- monster/compiler/variables.d | 4 +- monster/vm/arrays.d | 6 +- monster/vm/codestream.d | 4 +- monster/vm/error.d | 2 +- monster/vm/iterators.d | 4 +- monster/vm/mclass.d | 8 +-- monster/vm/mobject.d | 6 +- monster/vm/scheduler.d | 2 +- monster/vm/stack.d | 6 +- monster/vm/vm.d | 8 +-- mscripts/object.d | 70 +++++++++++++++++++++ mscripts/object.mn | 8 +++ mscripts/test.mn | 17 +++++ openmw.d | 2 + sound/audio.d | 2 + util/utfconvert.d | 114 ++++++++++++++++++++++++++++++++++ 27 files changed, 261 insertions(+), 43 deletions(-) create mode 100644 mscripts/object.d create mode 100644 mscripts/object.mn create mode 100644 mscripts/test.mn create mode 100644 util/utfconvert.d diff --git a/input/events.d b/input/events.d index ded0f6a7c..8953f2735 100644 --- a/input/events.d +++ b/input/events.d @@ -35,6 +35,8 @@ import scene.player; import bullet.bindings; +import monster.monster; + import ogre.bindings; import input.keys; @@ -290,6 +292,9 @@ extern(C) int d_frameStarted(float time) if(doExit) return 0; + // Run the Monster scheduler + scheduler.doFrame(); + musCumTime += time; if(musCumTime > musRefresh) { diff --git a/monster/compiler/assembler.d b/monster/compiler/assembler.d index 4b31887ca..e21cc4cbc 100644 --- a/monster/compiler/assembler.d +++ b/monster/compiler/assembler.d @@ -24,8 +24,8 @@ module monster.compiler.assembler; -import monster.minibos.string; -import monster.minibos.stdio; +import std.string; +import std.stdio; import monster.util.list; diff --git a/monster/compiler/expression.d b/monster/compiler/expression.d index 73446e769..a239d90ab 100644 --- a/monster/compiler/expression.d +++ b/monster/compiler/expression.d @@ -38,9 +38,9 @@ import monster.vm.mclass; import monster.vm.arrays; import monster.util.list; -import monster.minibos.string; -import monster.minibos.stdio; -import monster.minibos.utf : decode, toUTF32; +import std.string; +import std.stdio; +import std.utf : decode, toUTF32; alias Expression[] ExprArray; diff --git a/monster/compiler/functions.d b/monster/compiler/functions.d index 38b97b82d..05bc6da60 100644 --- a/monster/compiler/functions.d +++ b/monster/compiler/functions.d @@ -50,7 +50,7 @@ import monster.vm.mclass; import monster.vm.error; import monster.vm.fstack; -import monster.minibos.stdio; +import std.stdio; // One problem with these split compiler / vm classes is that we // likely end up with data (or at least pointers) we don't need, and a diff --git a/monster/compiler/operators.d b/monster/compiler/operators.d index ff5552269..7d7e2e394 100644 --- a/monster/compiler/operators.d +++ b/monster/compiler/operators.d @@ -32,7 +32,7 @@ import monster.compiler.types; import monster.vm.error; import monster.vm.arrays; -import monster.minibos.stdio; +import std.stdio; // Handles - ! ++ -- class UnaryOperator : Expression diff --git a/monster/compiler/properties.d b/monster/compiler/properties.d index a3d509c02..f5ede0ec9 100644 --- a/monster/compiler/properties.d +++ b/monster/compiler/properties.d @@ -27,7 +27,7 @@ import monster.compiler.scopes; import monster.compiler.types; import monster.compiler.assembler; -import monster.minibos.stdio; +import std.stdio; /* This module contains special scopes for builtin types. These are used to resolve type properties like .length for arrays and .min diff --git a/monster/compiler/scopes.d b/monster/compiler/scopes.d index c37a0273b..1fc0e4cfe 100644 --- a/monster/compiler/scopes.d +++ b/monster/compiler/scopes.d @@ -23,8 +23,8 @@ module monster.compiler.scopes; -import monster.minibos.stdio; -import monster.minibos.string; +import std.stdio; +import std.string; import monster.util.aa; diff --git a/monster/compiler/statement.d b/monster/compiler/statement.d index 5240412eb..287ff381e 100644 --- a/monster/compiler/statement.d +++ b/monster/compiler/statement.d @@ -24,8 +24,8 @@ module monster.compiler.statement; -import monster.minibos.string; -import monster.minibos.stdio; +import std.string; +import std.stdio; import monster.compiler.tokenizer; import monster.compiler.expression; diff --git a/monster/compiler/states.d b/monster/compiler/states.d index 6d580299a..74cacf6c6 100644 --- a/monster/compiler/states.d +++ b/monster/compiler/states.d @@ -34,7 +34,7 @@ import monster.vm.error; import monster.util.aa; -import monster.minibos.stdio; +import std.stdio; struct State { diff --git a/monster/compiler/tokenizer.d b/monster/compiler/tokenizer.d index 3eec9cd64..cdc36903d 100644 --- a/monster/compiler/tokenizer.d +++ b/monster/compiler/tokenizer.d @@ -24,9 +24,9 @@ module monster.compiler.tokenizer; -import monster.minibos.string; -import monster.minibos.stream; -import monster.minibos.stdio; +import std.string; +import std.stream; +import std.stdio; import monster.util.string : begins; diff --git a/monster/compiler/types.d b/monster/compiler/types.d index eb53156a4..5a3b43d5f 100644 --- a/monster/compiler/types.d +++ b/monster/compiler/types.d @@ -35,8 +35,8 @@ import monster.compiler.states; import monster.vm.mclass; import monster.vm.error; -import monster.minibos.stdio; -import monster.minibos.string; +import std.stdio; +import std.string; /* List of all type classes: diff --git a/monster/compiler/variables.d b/monster/compiler/variables.d index 140282149..cc9f2c97e 100644 --- a/monster/compiler/variables.d +++ b/monster/compiler/variables.d @@ -30,8 +30,8 @@ import monster.compiler.expression; import monster.compiler.scopes; import monster.compiler.block; -import monster.minibos.string; -import monster.minibos.stdio; +import std.string; +import std.stdio; import monster.vm.error; enum VarType diff --git a/monster/vm/arrays.d b/monster/vm/arrays.d index a459ddcb3..c5ea4da96 100644 --- a/monster/vm/arrays.d +++ b/monster/vm/arrays.d @@ -27,9 +27,9 @@ import monster.util.freelist; import monster.util.flags; import monster.vm.error; -import monster.minibos.string; -import monster.minibos.uni; -import monster.minibos.stdio; +import std.string; +import std.uni; +import std.stdio; // An index to an array. Array indices may be 0, unlike object indices // which span from 1 and upwards, and has 0 as the illegal 'null' diff --git a/monster/vm/codestream.d b/monster/vm/codestream.d index e4c9f832b..762758e45 100644 --- a/monster/vm/codestream.d +++ b/monster/vm/codestream.d @@ -24,8 +24,8 @@ module monster.vm.codestream; -import monster.minibos.string; -import monster.minibos.stdio; +import std.string; +import std.stdio; import monster.vm.error; import monster.compiler.linespec; diff --git a/monster/vm/error.d b/monster/vm/error.d index f12f5bd2b..268d5413f 100644 --- a/monster/vm/error.d +++ b/monster/vm/error.d @@ -26,7 +26,7 @@ module monster.vm.error; import monster.compiler.tokenizer; version(Tango) import tango.core.Exception; -import monster.minibos.string; +import std.string; class MonsterException : Exception { diff --git a/monster/vm/iterators.d b/monster/vm/iterators.d index 22f731271..493c785ff 100644 --- a/monster/vm/iterators.d +++ b/monster/vm/iterators.d @@ -30,8 +30,8 @@ import monster.vm.mclass; import monster.vm.mobject; import monster.util.flags; -import monster.minibos.string; -import monster.minibos.stdio; +import std.string; +import std.stdio; // An iterator index. typedef int IIndex; diff --git a/monster/vm/mclass.d b/monster/vm/mclass.d index 8ee58a75f..5a1e7846f 100644 --- a/monster/vm/mclass.d +++ b/monster/vm/mclass.d @@ -45,10 +45,10 @@ import monster.util.flags; import monster.util.freelist; import monster.util.string; -import monster.minibos.string; -import monster.minibos.stdio; -import monster.minibos.file; -import monster.minibos.stream; +import std.string; +import std.stdio; +import std.file; +import std.stream; // TODO: Needed to fix DMD/GDC template problems. Remove if this bug // is fixed. diff --git a/monster/vm/mobject.d b/monster/vm/mobject.d index 9db440dd2..51d6bde6d 100644 --- a/monster/vm/mobject.d +++ b/monster/vm/mobject.d @@ -32,9 +32,9 @@ import monster.compiler.states; import monster.compiler.variables; import monster.compiler.scopes; -import monster.minibos.string; -import monster.minibos.stdio; -import monster.minibos.utf; +import std.string; +import std.stdio; +import std.utf; // An index to a monster object. typedef int MIndex; diff --git a/monster/vm/scheduler.d b/monster/vm/scheduler.d index f9998ee8c..0575a3ce4 100644 --- a/monster/vm/scheduler.d +++ b/monster/vm/scheduler.d @@ -32,7 +32,7 @@ import monster.vm.error; import monster.vm.fstack; import monster.util.freelist; -import monster.minibos.string; +import std.string; // Enable minor safety checks - can be removed from release code. debug=safecheck; diff --git a/monster/vm/stack.d b/monster/vm/stack.d index 8745be4ec..3a83bdb87 100644 --- a/monster/vm/stack.d +++ b/monster/vm/stack.d @@ -24,9 +24,9 @@ module monster.vm.stack; -import monster.minibos.string; -import monster.minibos.stdio; -import monster.minibos.utf; +import std.string; +import std.stdio; +import std.utf; import monster.compiler.scopes; diff --git a/monster/vm/vm.d b/monster/vm/vm.d index 510ab726d..8444406c7 100644 --- a/monster/vm/vm.d +++ b/monster/vm/vm.d @@ -23,10 +23,10 @@ module monster.vm.vm; -import monster.minibos.string; -import monster.minibos.stdio; -import monster.minibos.uni; -import monster.minibos.c.string; +import std.string; +import std.stdio; +import std.uni; +import std.c.string; import monster.compiler.bytecode; import monster.compiler.linespec; diff --git a/mscripts/object.d b/mscripts/object.d new file mode 100644 index 000000000..6a5e91ef1 --- /dev/null +++ b/mscripts/object.d @@ -0,0 +1,70 @@ +module mscripts.object; + +import monster.monster; +import std.stdio; +import std.date; + +// Set up the base Monster classes we need in OpenMW +void initMonsterScripts() +{ + // Add the script directory + MonsterClass.addPath("mscripts/"); + + // Make sure the Object class is loaded + auto mc = new MonsterClass("Object", "object.mn"); + + // Bind various functions + mc.bind("print", { print(); }); + mc.bind("sleep", new IdleSleep); + + // Load and run the test script + mc = new MonsterClass("Test"); + mc.createObject().call("test"); +} + +// Write a message to screen +void print() +{ + AIndex[] args = stack.popAArray(); + + foreach(AIndex ind; args) + writef("%s ", arrays.getRef(ind).carr); + writefln(); +} + +// Sleep a given amount of time. Currently uses the system clock, but +// will later be optimized to use the already existing timing +// information from OGRE. +class IdleSleep : IdleFunction +{ + long getLong(MonsterObject *mo) + { return *(cast(long*)mo.extra); } + void setLong(MonsterObject *mo, long l) + { *(cast(long*)mo.extra) = l; } + + override: + bool initiate(MonsterObject *mo) + { + // Get the parameter + double secs = stack.popFloat; + + // Get current time + long newTime = getUTCtime(); + + // Calculate when we should return + newTime += secs*TicksPerSecond; + + // Store it + if(mo.extra == null) mo.extra = new long; + setLong(mo, newTime); + + // Schedule us + return true; + } + + bool hasFinished(MonsterObject *mo) + { + // Is it time? + return getUTCtime() >= getLong(mo); + } +} diff --git a/mscripts/object.mn b/mscripts/object.mn new file mode 100644 index 000000000..ed18a84bb --- /dev/null +++ b/mscripts/object.mn @@ -0,0 +1,8 @@ +// This is the base class of all OpenMW Monster classes. +class Object; + +// Sleeps a given amount of time +idle sleep(float seconds); + +// Print a message to screen +native print(char[][] msg...); diff --git a/mscripts/test.mn b/mscripts/test.mn new file mode 100644 index 000000000..ee769984d --- /dev/null +++ b/mscripts/test.mn @@ -0,0 +1,17 @@ +// A sample class +class Test : Object; + +test() +{ + state = printMessage; +} + +state printMessage +{ + // This state code will run as long as the object is in this state. + begin: + sleep(10); + print("Howdy from the world of Monster scripts!"); + print("This script is located in mscripts/test.mn. Check it out!"); + goto begin; +} diff --git a/openmw.d b/openmw.d index cd9e95c48..2973ca697 100644 --- a/openmw.d +++ b/openmw.d @@ -41,6 +41,7 @@ import core.memory; import core.config; import monster.util.string; +import mscripts.object; import sound.audio; @@ -125,6 +126,7 @@ void main(char[][] args) } initializeMemoryRegions(); + initMonsterScripts(); /* importSavegame("data/quiksave.ess"); diff --git a/sound/audio.d b/sound/audio.d index bf6f913b5..7d34f0a5b 100644 --- a/sound/audio.d +++ b/sound/audio.d @@ -26,6 +26,8 @@ module sound.audio; public import sound.sfx; public import sound.music; +import monster.monster; + import sound.al; import sound.alc; diff --git a/util/utfconvert.d b/util/utfconvert.d new file mode 100644 index 000000000..62083cad2 --- /dev/null +++ b/util/utfconvert.d @@ -0,0 +1,114 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.snaptoad.com/ + + This file (utfconvert.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.utfconvert; + +import std.utf; + +// A specialized version of std.utf.decode(). It returns a bool rather +// than throwing an exception. +private bool fdecode(char[] s, inout size_t idx) + { + size_t len = s.length; + dchar V; + size_t i = idx; + char u = s[i]; + + if (u & 0x80) + { uint n; + char u2; + + /* The following encodings are valid, except for the 5 and 6 byte + * combinations: + * 0xxxxxxx + * 110xxxxx 10xxxxxx + * 1110xxxx 10xxxxxx 10xxxxxx + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + for (n = 1; ; n++) + { + if (n > 4) + return false; // only do the first 4 of 6 encodings + if (((u << n) & 0x80) == 0) + { + if (n == 1) + return false; + break; + } + } + + // Pick off (7 - n) significant bits of B from first byte of octet + V = cast(dchar)(u & ((1 << (7 - n)) - 1)); + + if (i + (n - 1) >= len) + return false; // off end of string + + /* The following combinations are overlong, and illegal: + * 1100000x (10xxxxxx) + * 11100000 100xxxxx (10xxxxxx) + * 11110000 1000xxxx (10xxxxxx 10xxxxxx) + * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) + * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) + */ + u2 = s[i + 1]; + if ((u & 0xFE) == 0xC0 || + (u == 0xE0 && (u2 & 0xE0) == 0x80) || + (u == 0xF0 && (u2 & 0xF0) == 0x80) || + (u == 0xF8 && (u2 & 0xF8) == 0x80) || + (u == 0xFC && (u2 & 0xFC) == 0x80)) + return false; // overlong combination + + for (uint j = 1; j != n; j++) + { + u = s[i + j]; + if ((u & 0xC0) != 0x80) + return false; // trailing bytes are 10xxxxxx + V = (V << 6) | (u & 0x3F); + } + if (!isValidDchar(V)) + return false; + i += n; + } + else + { + V = cast(dchar) u; + i++; + } + + idx = i; + return true; + } + +// Converts any string to valid UTF8 so it can be safely printed. It +// does not translate from other encodings but simply replaces invalid +// characters with 'replace'. Does everything in place. +char[] makeUTF8(char[] str, char replace = '?') +{ + size_t idx = 0; + while(idx < str.length) + if(!fdecode(str, idx)) + str[idx++] = replace; + return str; +}