Preparation for console

git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@103 ea6a568a-9f4f-0410-981a-c910a81bb256
actorid
nkorslund 16 years ago
parent 714b724bf2
commit 1b01de4294

@ -38,7 +38,7 @@ bullet_cpp_files=$(bullet_cpp:%=bullet/cpp_%.cpp)
# All object files needed by openmw and esmtool
src := $(wildcard bsa/*.d) $(wildcard bullet/*.d) $(wildcard core/*.d) \
$(wildcard esm/*.d) $(wildcard input/*.d) $(wildcard nif/*.d) $(wildcard ogre/*.d) \
$(wildcard scene/*.d) $(wildcard sound/*.d) $(wildcard util/*.d)
$(wildcard scene/*.d) $(wildcard sound/*.d) $(wildcard util/*.d) $(wildcard gui/*.d)
src := $(src) $(wildcard mscripts/*.d)
src := $(src) monster/monster.d \
$(wildcard monster/vm/*.d) \

@ -35,8 +35,11 @@ extern(C):
// Initialize the dynamic world. Returns non-zero if an error occurs.
int bullet_init();
// Switch to the next physics mode
// Set physics modes
void bullet_nextMode();
void bullet_walk();
void bullet_fly();
void bullet_ghost();
// Warp the player to a specific location.
void bullet_movePlayer(float x, float y, float z);

@ -206,29 +206,45 @@ extern "C" int32_t bullet_init()
return 0;
}
// Set physics modes
extern "C" void bullet_walk()
{
g_physMode = PHYS_WALK;
cout << "Walk mode\n";
}
extern "C" void bullet_fly()
{
g_physMode = PHYS_FLY;
cout << "Fly mode\n";
}
extern "C" void bullet_ghost()
{
g_physMode = PHYS_GHOST;
cout << "Ghost mode\n";
}
// Switch to the next physics mode
extern "C" void bullet_nextMode()
{
g_physMode++;
if(g_physMode > PHYS_GHOST)
g_physMode = PHYS_WALK;
switch(g_physMode)
{
case PHYS_WALK:
cout << "Entering walking mode\n";
bullet_fly();
break;
case PHYS_FLY:
cout << "Entering flying mode\n";
bullet_ghost();
break;
case PHYS_GHOST:
cout << "Entering ghost mode\n";
bullet_walk();
break;
}
}
// Warp the player to a specific location. We do not bother setting
// rotation, since it's completely irrelevant for collision detection.
// rotation, since it's completely irrelevant for collision detection,
// and doubly so since the collision mesh is a sphere.
extern "C" void bullet_movePlayer(float x, float y, float z)
{
btTransform tr;

@ -164,7 +164,7 @@ struct NPC
skipRecord();
makeProto("Person");
makeProto();
// Clean this up a little later, eg. no point in storing the
// structs outside the function any longer. Same goes for most of

@ -0,0 +1,53 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (bindings.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 gui.bindings;
extern(C):
// GUI functions. Under development. The corresponding C++ functions
// are in ogre/cpp_mygui.cpp
typedef void* WidgetPtr;
void gui_setupGUI(int debugOut);
void gui_toggleGui();
void gui_setCellName(char *str);
// Get the widget type, as a string
char *gui_widgetType(WidgetPtr);
// Get the height or width of a widget. If the argument is null,
// return the size of the screen.
int gui_getHeight(WidgetPtr);
int gui_getWidth(WidgetPtr);
// Set various properties of a given widget
void gui_setCaption(WidgetPtr, char*);
void gui_setNeedMouseFocus(WidgetPtr, int);
void gui_setTextColor(WidgetPtr, float,float,float);
void gui_setCoord(WidgetPtr, int,int,int,int);
// Various ways to get or create widgets
WidgetPtr gui_loadLayout(char *file, char *prefix, WidgetPtr parent);
WidgetPtr gui_getChild(WidgetPtr, char*);
WidgetPtr gui_createText(char *skin, int x, int y, int w, int h, char *layer);

@ -21,11 +21,11 @@
*/
module ogre.gui;
module gui.gui;
import monster.monster;
import monster.vm.mclass;
import ogre.bindings;
import gui.bindings;
import std.string;
// Widget class and gui module
@ -57,7 +57,7 @@ class MWidget
isLayout = true;
prefix = format("%s", cast(void*)this);
widget = gui_loadLayout(layout.ptr, prefix.ptr, parent);
widget = gui_loadLayout(layout.toStringz(), prefix.toStringz(), parent);
if(widget is null)
fail("Layout " ~ layout ~ " is empty");
@ -91,7 +91,7 @@ class MWidget
name = prefix ~ name;
// Get the child widget
auto pt = gui_getChild(widget, name.ptr);
auto pt = gui_getChild(widget, name.toStringz());
if(pt is null)
fail("Widget has no child named " ~ name);
@ -163,7 +163,7 @@ void setCaption()
foreach(AIndex ind; args)
res ~= format("%s", arrays.getRef(ind).carr);
gui_setCaption(getOwner(), res.ptr);
gui_setCaption(getOwner(), toStringz(res));
}
void setNeedMouseFocus()
{ gui_setNeedMouseFocus(getOwner(), stack.popBool); }
@ -211,9 +211,9 @@ void text()
int y = stack.popInt();
int x = stack.popInt();
char[] skin = stack.popString8();
WidgetPtr ptr = gui_createText(skin.ptr,
WidgetPtr ptr = gui_createText(skin.toStringz(),
x,y,w,h,
layer.ptr);
layer.toStringz());
assert(widgetType(ptr) == "StaticText");
MWidget mw = new MWidget(ptr);
stack.pushObject(mw.mo);

@ -213,7 +213,7 @@ void initializeInput()
{
// Move the player into place. TODO: This isn't really input-related
// at all, and should be moved.
with(playerData.position)
with(*playerData.position)
{
ogre_moveCamera(position[0], position[1], position[2]);
ogre_setCameraRotation(rotation[0], rotation[1], rotation[2]);
@ -305,6 +305,11 @@ extern(C) int d_frameStarted(float time, int guiMode)
bullet_getPlayerPos(&x, &y, &z);
ogre_moveCamera(x,y,z);
// Store it in the player object
playerData.position.position[0] = x;
playerData.position.position[1] = y;
playerData.position.position[2] = z;
// Tell the sound scene that the player has moved
sndCumTime += time;
if(sndCumTime > sndRefresh)

@ -1180,12 +1180,26 @@ class ExprStatement : Statement
// Require a terminating semicolon or line break
bool term = true;
// True if 'left' was set in the constructor
bool leftSet = false;
this(Expression lft=null)
{
left = lft;
if(left !is null)
leftSet = true;
}
void parse(ref TokenArray toks)
{
if(toks.length == 0)
fail("Expected statement, found end of stream.");
loc = toks[0].loc;
left = Expression.identify(toks);
if(left is null)
{
if(toks.length == 0)
fail("Expected statement, found end of stream.");
left = Expression.identify(toks);
}
loc = left.loc;
Token tok;
@ -1219,7 +1233,8 @@ class ExprStatement : Statement
void resolve(Scope sc)
{
left.resolve(sc);
if(!leftSet)
left.resolve(sc);
loc = left.loc;
type = left.type;

@ -989,26 +989,66 @@ class FunctionCallExpr : Expression
fail("Parameter list expected ')'", toks);
}
this(Expression func, ref TokenArray toks)
// Special version of getParams that allow 'console-mode' grammar.
static void getParamsConsole(ref TokenArray toks,
out ExprArray parms,
out NamedParam[] named)
{
parms = null;
named = null;
// The param list is terminated by a semicolon or a newline
while(!isSep(toks))
{
if(toks.length == 0)
fail("Unexpected end of stream");
// Named paramter?
if(toks.length >= 3 && toks[1].type == TT.Equals)
{
NamedParam np;
reqNext(toks, TT.Identifier, np.name);
reqNext(toks, TT.Equals);
np.value = Expression.identify(toks);
named ~= np;
}
else
{
// Normal parameter
if(named.length)
fail("Cannot use non-named parameters after a named one",
toks[0].loc);
parms ~= Expression.identify(toks);
}
// Allow optional commas between parameters
isNext(toks, TT.Comma);
}
}
this(Expression func, ref TokenArray toks, bool console=false)
{
assert(func !is null);
fname = func;
loc = fname.loc;
// Parse the parameter list
getParams(toks, params, named);
// Parse the parameter list. The 'console' parameter determines
// whether we're using normal grammar rules:
// func(param1,param2)
// or console rules
// func param1 param2
if(console)
getParamsConsole(toks, params, named);
else
getParams(toks, params, named);
}
/* Might be used for D-like implicit function calling, eg. someFunc;
or (obj.prop)
this(Expression func) {}
We might also allow a special free-form function call syntax, eg.
func 1 2 3
where parens and commas are optional, and the list is terminated by
isSep (newline or ;). This is useful mostly for console mode.
*/
void parse(ref TokenArray toks) { assert(0); }
@ -1176,7 +1216,7 @@ class FunctionCallExpr : Expression
}
// Evaluate the parameters
void evalParams()
private void evalParams()
{
// Again, let's handle the vararg case separately
if(isVararg)
@ -1253,9 +1293,10 @@ class FunctionCallExpr : Expression
{
if(isCast)
{
// This is a type cast, not a function call.
// Just evaluate the expression. CastExpression takes care
// of everything automatically.
assert(params.length == 1);
assert(params[0] !is null);
params[0].eval();

@ -534,8 +534,8 @@ class DotOperator : OperatorExpr
type = member.type;
// Make sure we only call static members when the owner is a
// type.
if(ot.isMeta && !member.isStatic)
// type or a package.
if((ot.isMeta || ot.isPackage) && !member.isStatic)
fail("Can only access static members for " ~ owner.toString,
loc);
}

@ -1702,11 +1702,21 @@ class TypeofType : ReplacerType
// D.
class GenericType : InternalType
{
static GenericType sing;
this() { name = "var"; }
static bool canParse(TokenArray toks)
{ return isNext(toks, TT.Var); }
static GenericType getSingleton()
{
if(sing is null)
sing = new GenericType;
return sing;
}
override:
bool isVar() { return true; }

@ -576,6 +576,7 @@ class MemberExpr : Expression
isNext(toks, TT.Singleton) ||
isNext(toks, TT.State) ||
isNext(toks, TT.Clone) ||
isNext(toks, TT.Var) ||
isNext(toks, TT.Const);
}
@ -803,6 +804,13 @@ class MemberExpr : Expression
if(name.type == TT.Const || name.type == TT.Clone)
fail("Cannot use " ~ name.str ~ " as a variable", name.loc);
if(name.type == TT.Var)
{
type = GenericType.getSingleton();
vtype = VType.Special;
return;
}
// Look ourselves up in the local scope, and include imported
// scopes.
look = sc.lookupImport(name);
@ -851,6 +859,9 @@ class MemberExpr : Expression
void evalAsm()
{
if(type.isVar)
fail("Cannot use 'var' as an expression", loc);
// Hairy. But does the trick for now.
if(dotImport !is null && recurse)
{
@ -1011,6 +1022,7 @@ class VarDeclStatement : Statement
{
VarDeclaration[] vars;
bool reqSemi;
Type preKnownType = null;
// Pass 'true' to the constructor to require a semi-colon (used eg
// in for loops)
@ -1019,6 +1031,12 @@ class VarDeclStatement : Statement
reqSemi = rs;
}
// Used from the console, when the type is already known
this(Type type)
{
preKnownType = type;
}
static bool canParse(TokenArray toks)
{
if(Type.canParseRem(toks) &&
@ -1030,7 +1048,12 @@ class VarDeclStatement : Statement
void parse(ref TokenArray toks)
{
VarDeclaration varDec;
varDec = new VarDeclaration;
if(preKnownType !is null)
varDec = new VarDeclaration(preKnownType);
else
varDec = new VarDeclaration;
varDec.parse(toks);
vars ~= varDec;
loc = varDec.var.name.loc;

@ -134,19 +134,16 @@ class Console
void putln(char[] str) { put(str, true); }
Statement[] parse(TokenArray toks)
Statement[] parse(TokenArray toks, Scope sc)
{
Statement b = null;
Statement b;
Statement[] res;
repeat:
if(VarDeclStatement.canParse(toks))
{
if(!allowVar) fail("Variable declaration not allowed here");
b = new VarDeclStatement;
}
else if(CodeBlock.canParse(toks)) b = new CodeBlock;
b = null;
if(CodeBlock.canParse(toks)) b = new CodeBlock;
else if(IfStatement.canParse(toks)) b = new IfStatement;
else if(DoWhileStatement.canParse(toks)) b = new DoWhileStatement;
else if(WhileStatement.canParse(toks)) b = new WhileStatement;
@ -154,11 +151,24 @@ class Console
else if(ForeachStatement.canParse(toks)) b = new ForeachStatement;
else if(ImportStatement.canParse(toks)) b = new ImportStatement(true);
// If this is not one of the above, default to an expression
// statement.
else b = new ExprStatement;
if(b !is null)
{
// Parse and resolve
b.parse(toks);
b.resolve(sc);
}
else
{
// If this is not one of the above, default to a console
// statement.
auto es = new ConsoleStatement;
b = es;
// Parse and resolve in one operation.
es.parseResolve(toks, sc, allowVar);
}
b.parse(toks);
assert(b !is null);
res ~= b;
// Are there more tokens waiting for us?
@ -269,51 +279,58 @@ class Console
if(tokArr.length == 0)
return CR.Empty;
// Phase II, parse
// Phase II & III, parse and resolve
TokenArray toks = tokArr.arrayCopy();
Statement[] sts = parse(toks);
Statement[] sts = parse(toks, sc);
delete toks;
assert(sts.length >= 1);
// First, background the current thread (if any) and bring up
// our own.
// our own. This is necessary in order to keep the stack
// variables we make.
store = cthread;
if(store !is null)
store.background();
assert(trd !is null);
trd.foreground();
// We have to push ourselves on the function stack, or call()
// will see that it's empty and kill the thread upon exit
// We have to push ourselves on the function stack, or
// Function.call() will see that it's empty and kill the thread
// upon exit
trd.fstack.pushExt("Console");
// The rest must be performed separately for each statement on
// the line.
foreach(st; sts)
{
// Phase III, resolve
st.resolve(sc);
// Phase IV, compile
tasm.newFunc();
// Is it an expression?
auto es = cast(ExprStatement)st;
if(es !is null)
ExprStatement es;
// Is it an special console statement?
auto cs = cast(ConsoleStatement)st;
if(cs !is null)
{
// Yes. But is the type usable?
if(es.left.type.canCastTo(ArrayType.getString())
&& es.right is null)
// Yes. Is the client an expression?
es = cast(ExprStatement)cs.client;
if(es !is null)
{
// Yup. Get the type, and cast the expression to string.
scope auto ce = new
CastExpression(es.left, ArrayType.getString());
ce.eval();
// Ok. But is the type usable?
if(es.left.type.canCastTo(ArrayType.getString())
&& es.right is null)
{
// Yup. Get the type, and cast the expression to string.
scope auto ce = new
CastExpression(es.left, ArrayType.getString());
ce.eval();
}
else es = null;
}
else es = null;
}
// No expression is being used, so compile the statement
// normally.
if(es is null)
st.compile();
@ -336,28 +353,31 @@ class Console
// function frame, ie. the same way we treat function
// parameters. We do this by giving the variables negative
// indices.
auto vs = cast(VarDeclStatement)st;
if(vs !is null)
if(cs !is null)
{
// Add the new vars to the list
foreach(v; vs.vars)
{
varList ~= v.var;
// Add the size as well
varSize += v.var.type.getSize;
}
// Recalculate all the indices backwards from zero
int place = 0;
foreach_reverse(v; varList)
auto vs = cast(VarDeclStatement)cs.client;
if(vs !is null)
{
place -= v.type.getSize;
v.number = place;
// Add the new vars to the list
foreach(v; vs.vars)
{
varList ~= v.var;
// Add the size as well
varSize += v.var.type.getSize;
}
// Recalculate all the indices backwards from zero
int place = 0;
foreach_reverse(v; varList)
{
place -= v.type.getSize;
v.number = place;
}
// Reset the scope stack counters
sc.reset();
}
// Reset the scope stack counters
sc.reset();
}
}
@ -443,3 +463,71 @@ class Console
}
}
}
// Statement that handles variable declarations, function calls and
// expression statements in consoles. Since these are gramatically
// similar, we need the type to determine which
class ConsoleStatement : Statement
{
// Used for variables and expression statements
Statement client;
// Used for function calls
FunctionCallExpr func;
void parseResolve(ref TokenArray toks, Scope sc, bool allowVar)
{
assert(toks.length != 0);
// Get the first expression
auto first = Expression.identify(toks);
// And the type right away
first.resolve(sc);
auto type = first.type;
assert(type !is null);
// Type? If so, it's a variable declaration
if((type.isMeta || type.isVar) && allowVar)
{
if(type.isMeta) type = type.getBase();
client = new VarDeclStatement(type);
}
// Function?
else if(type.isFunc)
func = new FunctionCallExpr(first, toks, true);
// It's an expression statement
else
client = new ExprStatement(first);
if(client !is null)
{
client.parse(toks);
client.resolve(sc);
}
else
{
assert(func !is null);
func.resolve(sc);
}
}
override:
void parse(ref TokenArray) { assert(0); }
void resolve(Scope sc) { assert(0); }
void compile()
{
if(client !is null)
{
client.compile();
return;
}
assert(func !is null);
func.evalPop();
}
}

@ -116,9 +116,13 @@ long execLimit = 10000000;
bool defaultLogToStdout = false;
// If true, all function stack operations (pushes and pops) are logged
// with dbg.log().
// with dbg.log(), and all logged messages are indented according to
// the current fstack level.
bool logFStack = true;
// If true, log when threads are put into the background/forground.
bool logThreads = true;
/*********************************************************

@ -167,6 +167,9 @@ struct Thread
list.remove(this);
list = null;
assert(isDead);
static if(logThreads)
dbg.log(format("------ killing thread=%s ------", getIndex));
}
// Stop the execution of a thread and cancel any scheduling.

@ -0,0 +1,31 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (console.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/ .
*/
class Console
// This class contains all the functions available to the ingame
// console.
import io;
import game;

@ -0,0 +1,25 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (npc.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/ .
*/
class NPC : Person

@ -0,0 +1,27 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (player.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/ .
*/
singleton player : Person
name="Player Name"
level = 5 // Just an example value

@ -28,9 +28,11 @@ import monster.compiler.scopes : global;
import monster.modules.timer;
import core.config;
import ogre.gui;
import gui.gui;
import scene.player;
import std.string;
import std.stdio;
// Set up the base Monster classes we need in OpenMW
void initMonsterScripts()
@ -45,6 +47,9 @@ void initMonsterScripts()
// Get the Config singleton object
config.mo = vm.load("Config").getSing();
// Set up the player object.
playerData.setup();
// Set up the GUI Monster module
setupGUIScripts();
}
@ -62,7 +67,6 @@ void runGUIScripts()
// This should probably not be here:
import monster.vm.dbg;
import std.string;
extern(C):
void dbg_trace(char*str) { dbg.trace(toString(str)); }

@ -164,28 +164,3 @@ void ogre_moveCameraRel(float x, float y, float z);
// Insert a raw RGBA image into the texture system.
//void ogre_insertTexture(char *name, int width, int height, void *data);
// GUI functions. Under development.
typedef void* WidgetPtr;
void gui_setupGUI(int debugOut);
void gui_toggleGui();
void gui_setCellName(char *str);
// Get the widget type, as a string
char *gui_widgetType(WidgetPtr);
// Get the height or width of a widget. If the argument is null,
// return the size of the screen.
int gui_getHeight(WidgetPtr);
int gui_getWidth(WidgetPtr);
// Set various properties of a given widget
void gui_setCaption(WidgetPtr, char*);
void gui_setNeedMouseFocus(WidgetPtr, int);
void gui_setTextColor(WidgetPtr, float,float,float);
void gui_setCoord(WidgetPtr, int,int,int,int);
// Various ways to get or create widgets
WidgetPtr gui_loadLayout(char *file, char *prefix, WidgetPtr parent);
WidgetPtr gui_getChild(WidgetPtr, char*);
WidgetPtr gui_createText(char *skin, int x, int y, int w, int h, char *layer);

@ -48,7 +48,7 @@ extern "C" int32_t ogre_configure(
{
// Set up logging first
new LogManager;
Log *log = LogManager::getSingleton().createLog("default");
Log *log = LogManager::getSingleton().createLog("Ogre.log");
if(debugOut)
// Full log detail

@ -24,7 +24,9 @@ extern "C" int32_t gui_getWidth(MyGUI::WidgetPtr p)
// Set various properties of a given widget
extern "C" void gui_setCaption(MyGUI::WidgetPtr p, char* s)
{ p->setCaption(s); }
{
p->setCaption(s);
}
extern "C" void gui_setNeedMouseFocus(MyGUI::WidgetPtr p, int32_t b)
{ p->setNeedMouseFocus(b); }

@ -30,6 +30,7 @@ import std.file;
import ogre.ogre;
import ogre.bindings;
import gui.bindings;
import bullet.bullet;

@ -453,7 +453,7 @@ class CellData
{
// Create a creature, based on current player level.
LiveCreature ls;
ls.m = l.instCreature(playerData.level);
ls.m = l.instCreature(*playerData.level);
if(ls.m != null)
{
// Note that this clones a creature object, not a
@ -565,7 +565,7 @@ class CellData
if(door && !playerData.posSet)
{
playerData.posSet = true;
playerData.position = *pos;
*playerData.position = *pos;
}
}
} // End of while(hasMoreSubs)

@ -24,6 +24,7 @@
module scene.player;
import ogre.ogre;
import monster.monster;
/*
* Contains essential data about the player and other current game
@ -34,14 +35,30 @@ PlayerData playerData;
struct PlayerData
{
// Position and rotation. The rotation is not updated continuously,
// only the position.
Placement position;
// Just an example value, we use it for resolving leveled lists
// (lists that determine eg. what creatures to put in a cave based
// on what level the player is.)
short level = 5;
MonsterObject *mo;
Placement *position;
int *level;
// Set up the player object. This is still pretty hackish and
// temporary.
void setup()
{
assert(mo is null);
mo = vm.load("game.player").createObject;
level = mo.getIntPtr("level");
// Still an ugly hack
position = cast(Placement*)mo.getFloatPtr("x");
}
/*
char[] getName()
{
assert(mo !is null);
return mo.getString8("name");
}
*/
// Temp. way of selecting start point - used in celldata
bool posSet = false;

Loading…
Cancel
Save