1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-03 07:19:41 +00:00

Started implementing ALL in-game objects as Monster scripts.

git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@72 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
nkorslund 2008-11-17 20:11:55 +00:00
parent c2d992c8f0
commit 76295fbd45
35 changed files with 466 additions and 62 deletions

View file

@ -25,6 +25,7 @@ module esm.defs;
public import std.string;
public import monster.util.string;
import monster.monster;
/*
* Types and definitions related to parsing esm and esp files
@ -135,3 +136,50 @@ align(1) struct ENAMstruct
static assert(ENAMstruct.sizeof==24);
}
// Common stuff for all the load* structs
template LoadTT(T)
{
LoadState state;
char[] name, id;
MonsterObject *proto;
static MonsterClass mc;
void makeProto(char[] clsName = null)
{
// Use the template type name as the Monster class name if none
// is specified.
if(clsName == "")
{
clsName = typeid(T).toString;
// Remove the module name
int i = clsName.rfind('.');
if(i != -1)
clsName = clsName[i+1..$];
}
// Set up a prototype object
if(mc is null)
mc = MonsterClass.find(clsName);
proto = mc.createObject();
proto.setString8("id", id);
proto.setString8("name", name);
static if(is(typeof(data.weight) == float))
{
proto.setFloat("weight", data.weight);
proto.setInt("value", data.value);
}
static if(is(typeof(data.enchant)==int))
proto.setInt("enchant", data.enchant);
static if(is(typeof(data.health)==int))
proto.setInt("health", data.health);
}
}
template LoadT() { mixin LoadTT!(typeof(*this)); }

View file

@ -1,8 +1,8 @@
module esm.imports;
/* This is a file that imports common modules used by the load*.d
record loaders. It is really a cut down version of the start of
records.d.
record loaders. It is really a cut down version of what used to be
the start of records.d.
This file MUST NOT import records.d - directly or indirectly -
because that will trigger a nice three page long list of template
@ -41,4 +41,7 @@ import esm.loadscpt;
import esm.loadsoun;
import esm.loadspel;
import esm.loadench;
import monster.monster;
}

View file

@ -36,10 +36,8 @@ import esm.imports;
struct Activator
{
char[] id;
LoadState state;
mixin LoadT!();
char[] name;
Script *script;
MeshIndex model;
@ -48,6 +46,8 @@ struct Activator
model = getMesh();
name = getHNString("FNAM");
script = getHNOPtr!(Script)("SCRI", scripts);
makeProto();
}}
}
ListID!(Activator) activators;

View file

@ -30,9 +30,6 @@ import esm.imports;
struct Potion
{
char[] id;
LoadState state;
align(1) struct ALDTstruct
{
float weight;
@ -43,7 +40,7 @@ struct Potion
ALDTstruct data;
char[] name;
mixin LoadT!();
MeshIndex model;
IconIndex icon;
@ -69,6 +66,8 @@ struct Potion
readHExact(&effects.array[$-1], effects.array[$-1].sizeof);
}
makeProto();
proto.setInt("autoCalc", data.autoCalc);
}}
}
ListID!(Potion) potions;

View file

@ -30,9 +30,6 @@ import esm.imports;
struct Apparatus
{
char[] id, name;
LoadState state;
enum AppaType : int
{
MortarPestle = 0,
@ -50,6 +47,8 @@ struct Apparatus
static assert(AADTstruct.sizeof == 16);
}
mixin LoadT!();
AADTstruct data;
MeshIndex model;
IconIndex icon;
@ -62,6 +61,11 @@ struct Apparatus
readHNExact(&data, data.sizeof, "AADT");
script = getHNOPtr!(Script)("SCRI", scripts);
icon = getIcon();
makeProto();
proto.setFloat("quality", data.quality);
proto.setInt("type", data.type);
}}
}
ListID!(Apparatus) appas;

View file

@ -116,8 +116,7 @@ struct Armor
AODTstruct data;
char[] name, id;
LoadState state;
mixin LoadT!();
PartReferenceList parts;
@ -138,6 +137,11 @@ struct Armor
parts.load();
enchant = getHNOPtr!(Enchantment)("ENAM", enchants);
makeProto();
proto.setInt("type", data.type);
proto.setInt("armor", data.armor);
}}
}
ListID!(Armor) armors;

View file

@ -74,8 +74,8 @@ struct BodyPart
BYDTstruct data;
char[] name, id;
LoadState state;
mixin LoadT;
MeshIndex model;
void load()
@ -83,6 +83,9 @@ struct BodyPart
model = getMesh();
name = getHNString("FNAM");
readHNExact(&data, data.sizeof, "BYDT");
// don't need to run makeProto here yet, no BodyPart monster
// class.
}}
}

View file

@ -44,7 +44,9 @@ struct Book
IconIndex icon;
Script *script;
Enchantment *enchant;
char[] name, text, id;
mixin LoadT;
char[] text;
LoadState state;
@ -57,6 +59,11 @@ struct Book
icon = getIcon();
text = getHNOString("TEXT");
enchant = getHNOPtr!(Enchantment)("ENAM", enchants);
makeProto();
proto.setInt("skillID", data.skillID);
proto.setBool("isScroll", data.isScroll != 0);
}}
}
ListID!(Book) books;

View file

@ -30,9 +30,9 @@ import esm.imports;
struct BirthSign
{
LoadState state;
char[] description;
char[] id, name, description;
mixin LoadT;
TextureIndex texture;
@ -48,6 +48,8 @@ struct BirthSign
description = getHNOString("DESC");
powers.load();
// No monster class equivalent yet
}}
}
ListID!(BirthSign) birthSigns;

View file

@ -72,8 +72,9 @@ struct Class
static assert(CLDTstruct.sizeof == 60);
}
LoadState state;
char[] id, name, description;
mixin LoadT;
char[] description;
CLDTstruct data;
void load()
@ -85,6 +86,8 @@ struct Class
esFile.fail("Unknown bool value");
description = esFile.getHNOString("DESC");
// no makeProto yet
}
}
ListID!(Class) classes;

View file

@ -50,15 +50,15 @@ struct Clothing
Type type;
float weight;
short value;
short enchantPoints;
short enchant;
static assert(CTDTstruct.sizeof == 12);
}
CTDTstruct data;
LoadState state;
char[] id, name;
mixin LoadT;
PartReferenceList parts;
MeshIndex model;
@ -78,6 +78,9 @@ struct Clothing
parts.load();
enchant = getHNOPtr!(Enchantment)("ENAM", enchants);
makeProto();
proto.setInt("type", data.type);
}}
}
ListID!(Clothing) clothes;

View file

@ -69,9 +69,6 @@ struct Container
Unknown = 8
}
char[] id, name;
LoadState state;
MeshIndex model;
Script *script;
@ -79,6 +76,8 @@ struct Container
Flags flags;
InventoryList inventory;
mixin LoadT!();
void load()
{with(esFile){
model = getMesh();
@ -100,6 +99,9 @@ struct Container
script = getHNOPtr!(Script)("SCRI", scripts);
inventory.load();
makeProto();
proto.setFloat("weight", weight);
}}
}

View file

@ -30,13 +30,12 @@ import esm.imports;
struct Door
{
LoadState state;
char[] id, name;
MeshIndex model;
Script *script;
Sound* openSound, closeSound;
mixin LoadT!();
void load()
{with(esFile){
model = getMesh();
@ -44,6 +43,8 @@ struct Door
script = getHNOPtr!(Script)("SCRI", scripts);
openSound = getHNOPtr!(Sound)("SNAM", sounds);
closeSound = getHNOPtr!(Sound)("ANAM", sounds);
makeProto();
}}
}
ListID!(Door) doors; // Break on through

View file

@ -29,9 +29,6 @@ import esm.imports;
struct Light
{
char[] id;
LoadState state;
enum Flags : uint
{
Dynamic = 0x001,
@ -59,14 +56,14 @@ struct Light
LHDTstruct data;
char[] name;
MeshIndex model;
IconIndex icon;
mixin LoadT!();
Sound* sound;
Script* script;
MeshIndex model;
IconIndex icon;
void load()
{with(esFile){
model = getMesh();
@ -77,6 +74,14 @@ struct Light
script = getHNOPtr!(Script)("SCRI", scripts);
sound = getHNOPtr!(Sound)("SNAM", sounds);
// Stash the data in the Monster object prototype
makeProto();
proto.setUint("flags", data.flags);
proto.setFloat("lifetime", data.time);
proto.setInt("radius", data.radius);
}}
}
ListID!(Light) lights;

View file

@ -71,8 +71,7 @@ struct Weapon
WPDTstruct data;
LoadState state;
char[] name, id;
mixin LoadT!();
MeshIndex model;
IconIndex icon;
@ -87,6 +86,11 @@ struct Weapon
script = getHNOPtr!(Script)("SCRI", scripts);
icon = getOIcon();
enchant = getHNOPtr!(Enchantment)("ENAM", enchants);
makeProto();
proto.setFloat("speed", data.speed);
proto.setFloat("reach", data.reach);
}}
}
ListID!(Weapon) weapons;

View file

@ -393,6 +393,8 @@ struct Assembler
addi(i);
}
void cloneObj() { cmd(BC.Clone); }
// Copy the topmost int on the stack
void dup() { cmd(BC.Dup); }

View file

@ -69,6 +69,12 @@ enum BC
// giving the class index (in the file lookup
// table)
Clone, // Clones an object - create a new object of
// the same class, then copy variable values
// and state from the old object to the
// new. Replaces the object index on the stack
// with the new index.
Jump, // Jump to given position (int)
JumpZ, // Pop a value, if it is zero then jump to

View file

@ -1004,6 +1004,7 @@ class VariableExpr : MemberExpression
isNext(toks, TT.Identifier) ||
isNext(toks, TT.Singleton) ||
isNext(toks, TT.State) ||
isNext(toks, TT.Clone) ||
isNext(toks, TT.Const);
}
@ -1146,6 +1147,9 @@ class VariableExpr : MemberExpression
if(name.type == TT.Const)
fail("Cannot use const as a variable", name.loc);
if(name.type == TT.Clone)
fail("Cannot use clone as a variable", name.loc);
// These are special cases that work both as properties
// (object.state) and as non-member variables (state=...) inside
// class functions / state code. Since we already handle them

View file

@ -159,6 +159,8 @@ class ClassProperties : SimplePropertyScope
{
super("ClassProperties");
insert("clone", "owner", { tasm.cloneObj(); });
// For testing purposes. Makes 'singleton' an alias for the
// first variable in the data segment. This might actually not
// be far from how the end result would work - the singleton

View file

@ -537,6 +537,41 @@ final class MonsterClass
return top;
}
// Create a new object based on an existing object
MonsterObject* createClone(MonsterObject *source)
{
requireCompile();
assert(source.tree.length == tree.length);
assert(source.thread.topObj == source,
"createClone can only clone the topmost object");
// Create a new thread
CodeThread *trd = threads.getNew();
// Loop through the objects in the source tree, and clone each
// of them
MonsterObject* otree[] = source.tree.dup;
foreach(i, ref obj; otree)
{
obj = obj.cls.getClone(obj);
obj.tree = otree[0..i+1];
obj.thread = trd;
}
// Pick out the top object
MonsterObject* top = otree[$-1];
assert(top !is null);
// Initialize the thread
trd.initialize(top);
// Set the same state
trd.setState(source.thread.getState(), null);
return top;
}
// Free an object and its thread
void deleteObject(MonsterObject *obj)
{
@ -757,6 +792,46 @@ final class MonsterClass
// Point to the static data segment
obj.sdata = sdata;
obj.extra = null;
// Call the custom native constructor
if(constType != FuncType.Native)
{
fstack.pushNConst(obj);
if(constType == FuncType.NativeDDel)
dg_const();
else if(constType == FuncType.NativeDFunc)
fn_const();
else if(constType == FuncType.NativeCFunc)
c_const();
fstack.pop();
}
return obj;
}
// Clone an existing object
MonsterObject *getClone(MonsterObject *source)
{
assert(source !is null);
assert(source.cls is this);
assert(source.data.length == data.length);
assert(source.sdata.ptr is sdata.ptr);
requireCompile();
MonsterObject *obj = objects.getNew();
// Set the class
obj.cls = this;
// TODO: Fix memory management here too.
// Copy the data segment from the source
obj.data = source.data.dup;
// Point to the static data segment
obj.sdata = sdata;
obj.extra = null;
// Call the custom native constructor
if(constType != FuncType.Native)

View file

@ -69,6 +69,7 @@ struct MonsterObject
// the MonsterClass.
MonsterObject* tree[];
/*******************************************************
* *
* Functions for object handling *
@ -98,6 +99,16 @@ struct MonsterObject
cls.deleteObject(this);
}
// Create a clone of this object. Note that this will always clone
// and return the top object (thread.topObj), regardless of which
// object in the list it is called on. In other words, the class
// mo.cls is not always the same as mo.clone().cls.
MonsterObject *clone()
{
auto t = thread.topObj;
return t.cls.createClone(t);
}
/*******************************************************
* *
* Casting / polymorphism functions *

View file

@ -480,6 +480,10 @@ struct CodeThread
.createObject());
break;
case BC.Clone:
stack.pushObject(stack.popObject().clone());
break;
case BC.Jump:
code.jump(code.getInt);
break;

View file

@ -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 (activator.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 Activator : GameObject;

View file

@ -0,0 +1,28 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (apparatus.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/ .
*/
// Covers all alchemy apparatus - mortars, retorts, etc
class Apparatus : InventoryItem;
float quality;
int type;

View file

@ -0,0 +1,28 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (armor.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/ .
*/
// Covers all weapons and projectile weapons you can carry (like
// arrows and throwable items.)
class Armor : Repairable;
int type, armor;

View file

@ -0,0 +1,28 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (book.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 Book : EnchantItem;
bool isScroll;
int skillID; // Skill that is enhanced by reading this book, if any

View file

@ -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 (clothing.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/ .
*/
// All items that can be repaired (weapons and armor)
class Clothing : EnchantItem;
int type;

View file

@ -0,0 +1,26 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (container.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 Container : LockedObject;
float weight; // Not sure, might be max total weight allowed?

View file

@ -4,7 +4,7 @@
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (equipitem.mn) is part of the OpenMW package.
This file (enchantitem.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
@ -21,7 +21,7 @@
*/
// Anything that can be equiped, like clothes, armor and weapons.
class EquipItem : InventoryItem;
// Items that can be enchanted
class EnchantItem : InventoryItem;
int enchant;

View file

@ -40,6 +40,8 @@ float r1, r2, r3;
float scale;
char[] name, id;
// Various variables that are currently unused. Most of the strings
// will be replaced by object references at some point.

View file

@ -26,5 +26,6 @@ class Light : InventoryItem;
// Time left in seconds (for carried lights)
float lifetime;
// Is this a carryable light?
bool carry;
int radius;
uint flags;

View file

@ -0,0 +1,26 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (potion.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 Potion : InventoryItem;
int autoCalc;

View file

@ -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 (repairable.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/ .
*/
// All items that can be repaired (weapons and armor)
class Repairable : EnchantItem;
int health;

View file

@ -21,11 +21,11 @@
*/
// Weapons (This is just an example, it's not used for anything yet.)
class Weapon : EquipItem;
// Covers all weapons and carry-able projectiles.
class Weapon : Repairable;
float speed, reach;
// Not set yet.
bool magical, silver;
bool isTwohanded;
bool twoHanded;

View file

@ -39,7 +39,8 @@ import sound.audio;
import scene.player;
// Generic version of a "live" object
// Generic version of a "live" object. Do we even need this at all?
// No, I don't think so.
struct GenLive(T)
{
// Instance of class GameObject or a derived class (depending on
@ -259,16 +260,13 @@ class CellData
private:
static
MonsterClass gameObjC, doorC, lightC, lockedC;
MonsterClass gameObjC;
void setup()
{
if(gameObjC !is null) return;
gameObjC = new MonsterClass("GameObject");
doorC = new MonsterClass("Door");
lightC = new MonsterClass("Light");
lockedC = new MonsterClass("LockedObject");
gameObjC = MonsterClass.find("GameObject");
}
void loadReferences()
@ -329,24 +327,20 @@ class CellData
{
LiveLight ls;
ls.m = m;
ls.obj = lightC.createObject;
ls.obj = m.proto.clone();
mo = ls.obj;
mo.setFloat("lifetime", m.data.time);
bool carry = (m.data.flags&Light.Flags.Carry) != 0;
mo.setBool("carry", carry);
if(carry)
lights.insert(ls);
else
statLights.insert(ls);
}
else if(Container *c = it.getContainer())
{
LiveContainer ls;
ls.m = c;
ls.obj = lockedC.createObject;
ls.obj = c.proto.clone();
mo = ls.obj;
containers.insert(ls);
container = true;
@ -356,7 +350,7 @@ class CellData
{
LiveDoor ls;
ls.m = d;
ls.obj = doorC.createObject;
ls.obj = d.proto.clone();
mo = ls.obj;
doors.insert(ls);
door = true;
@ -416,7 +410,7 @@ class CellData
{
LiveWeapon ls;
ls.m = m;
ls.obj = gameObjC.createObject;
ls.obj = m.proto.clone();
mo = ls.obj;
weapons.insert(ls);
}