Merge remote branch 'zini/master' into gui-windows

This commit is contained in:
Jan Borsodi 2010-10-23 01:13:11 +02:00
commit 38b434771a
40 changed files with 2919 additions and 121 deletions

3
apps/doc.hpp Normal file
View file

@ -0,0 +1,3 @@
// Note: This is not a regular source file.
/// \defgroup apps Applications

View file

@ -184,11 +184,14 @@ set(GAMECLASS_HEADER
source_group(apps\\openmw\\mwclass FILES ${GAMECLASS} ${GAMECLASS_HEADER})
set(GAMEMECHANICS
mwmechanics/mechanicsmanager.cpp)
mwmechanics/mechanicsmanager.cpp
mwmechanics/magiceffects.cpp
)
set(GAMEMECHANICS_HEADER
mwmechanics/mechanicsmanager.hpp
mwmechanics/stat.hpp
mwmechanics/creaturestats.hpp
mwmechanics/magiceffects.hpp
)
source_group(apps\\openmw\\mwmechanics FILES ${GAMEMECHANICS} ${GAMEMECHANICS_HEADER})

44
apps/openmw/doc.hpp Normal file
View file

@ -0,0 +1,44 @@
// Note: This is not a regular source file.
/// \ingroup apps
/// \defgroup openmw OpenMW
/// \namespace OMW
/// \ingroup openmw
/// \brief Integration of OpenMW-subsystems
/// \namespace MWDialogue
/// \ingroup openmw
/// \brief NPC dialogues
/// \namespace MWMechanics
/// \ingroup openmw
/// \brief Game mechanics and NPC-AI
/// \namespace MWSound
/// \ingroup openmw
/// \brief Sound & music
/// \namespace MWGUI
/// \ingroup openmw
/// \brief HUD and windows
/// \namespace MWRender
/// \ingroup openmw
/// \brief Rendering via Ogre
/// \namespace MWWorld
/// \ingroup openmw
/// \brief World data
/// \namespace MWClass
/// \ingroup openmw
/// \brief Workaround for non-OOP design of the record system
/// \namespace MWInput
/// \ingroup openmw
/// \brief User input and character controls
/// \namespace MWScript
/// \ingroup openmw
/// \brief MW-specific script extentions and integration of the script system into OpenMW

View file

@ -117,6 +117,7 @@ OMW::Engine::Engine()
, mVerboseScripts (false)
, mNewGame (false)
, mUseSound (true)
, mCompileAll (false)
, mScriptManager (0)
, mScriptContext (0)
, mGuiManager (0)
@ -278,9 +279,20 @@ void OMW::Engine::go()
// load cell
ESM::Position pos;
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
mEnvironment.mWorld->changeCell (mCellName, pos);
pos.pos[2] = 0;
if (const ESM::Cell *exterior = mEnvironment.mWorld->getExterior (mCellName))
{
mEnvironment.mWorld->indexToPosition (exterior->data.gridX, exterior->data.gridY,
pos.pos[0], pos.pos[1], true);
mEnvironment.mWorld->changeToExteriorCell (pos);
}
else
{
pos.pos[0] = pos.pos[1] = 0;
mEnvironment.mWorld->changeCell (mCellName, pos);
}
// Sets up the input system
MWInput::MWInputManager input(mOgre, mEnvironment.mWorld->getPlayerPos(),
@ -305,6 +317,29 @@ void OMW::Engine::go()
std::cout << " Music Error: " << e.what() << "\n";
}
// scripts
if (mCompileAll)
{
typedef ESMS::ScriptListT<ESM::Script>::MapType Container;
Container scripts = mEnvironment.mWorld->getStore().scripts.list;
int count = 0;
int success = 0;
for (Container::const_iterator iter (scripts.begin()); iter!=scripts.end(); ++iter, ++count)
if (mScriptManager->compile (iter->first))
++success;
if (count)
std::cout
<< "compiled " << success << " of " << count << " scripts ("
<< 100*static_cast<double> (success)/count
<< "%)"
<< std::endl;
}
// Start the main rendering loop
mOgre.start();
@ -345,3 +380,8 @@ void OMW::Engine::activate()
interpreterContext.executeActivation();
}
}
void OMW::Engine::setCompileAll (bool all)
{
mCompileAll = all;
}

View file

@ -60,6 +60,7 @@ namespace OMW
bool mVerboseScripts;
bool mNewGame;
bool mUseSound;
bool mCompileAll;
MWWorld::Environment mEnvironment;
MWScript::ScriptManager *mScriptManager;
@ -127,6 +128,9 @@ namespace OMW
/// Activate the focussed object.
void activate();
/// Compile all scripts (excludign dialogue scripts) at startup?
void setCompileAll (bool all);
};
}

View file

@ -33,7 +33,7 @@ using namespace std;
bool parseOptions (int argc, char**argv, OMW::Engine& engine)
{
// Create a local alias for brevity
namespace bpo = boost::program_options;
namespace bpo = boost::program_options;
bpo::options_description desc (
"Syntax: openmw <options>\nAllowed options");
@ -43,23 +43,24 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine)
("data", bpo::value<std::string>()->default_value ("data"),
"set data directory")
("start", bpo::value<std::string>()->default_value ("Beshara"),
"set initial cell (only interior cells supported at the moment")
"set initial cell")
("master", bpo::value<std::string>()->default_value ("Morrowind"),
"master file")
( "debug", "debug mode" )
( "nosound", "disable all sound" )
( "script-verbose", "verbose script output" )
( "new-game", "activate char gen/new game mechanics" )
( "script-all", "compile all scripts (excluding dialogue scripts) at startup")
;
bpo::variables_map variables;
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
std::string configFilePath(macBundlePath() + "/Contents/MacOS/openmw.cfg");
std::ifstream configFile (configFilePath.c_str());
#else
std::ifstream configFile ("openmw.cfg");
#endif
#endif
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
@ -78,19 +79,22 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine)
engine.setDataDir (variables["data"].as<std::string>());
engine.setCell (variables["start"].as<std::string>());
engine.addMaster (variables["master"].as<std::string>());
if (variables.count ("debug"))
engine.enableDebugMode();
if (variables.count ("nosound"))
engine.disableSound();
if (variables.count ("script-verbose"))
engine.enableVerboseScripts();
if (variables.count ("new-game"))
engine.setNewGame();
if (variables.count ("script-all"))
engine.setCompileAll (true);
return true;
}
@ -100,7 +104,7 @@ int main(int argc, char**argv)
try
{
OMW::Engine engine;
if (parseOptions (argc, argv, engine))
{
engine.go();
@ -111,7 +115,7 @@ int main(int argc, char**argv)
cout << "\nERROR: " << e.what() << endl;
return 1;
}
return 0;
}

View file

@ -560,13 +560,19 @@ void WindowManager::onClassChoice(MyGUI::WidgetPtr, int _index)
}
}
void WindowManager::showClassQuestionDialog()
namespace MWGui
{
struct Step
{
const char* text;
const char* buttons[3];
};
}
void WindowManager::showClassQuestionDialog()
{
static boost::array<Step, 2> steps = { {
{"On a clear day you chance upon a strange animal, its legs trapped in a hunter's clawsnare. Judging from the bleeding, it will not survive long.",
{"Use herbs from your pack to put it to sleep?",

View file

@ -1,7 +1,11 @@
#ifndef GAME_MWMECHANICS_CREATURESTATS_H
#define GAME_MWMECHANICS_CREATURESTATS_H
#include <set>
#include <string>
#include "stat.hpp"
#include "magiceffects.hpp"
namespace MWMechanics
{
@ -10,6 +14,8 @@ namespace MWMechanics
Stat<int> mAttributes[8];
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
int mLevel;
std::set<std::string> mAbilities;
MagicEffects mMagicEffects;
};
}

View file

@ -0,0 +1,118 @@
#include "magiceffects.hpp"
#include <stdexcept>
#include <components/esm/defs.hpp>
namespace MWMechanics
{
EffectKey::EffectKey() : mId (0), mArg (-1) {}
EffectKey::EffectKey (const ESM::ENAMstruct& effect)
{
mId = effect.effectID;
mArg = -1;
if (effect.skill!=-1)
mArg = effect.skill;
if (effect.attribute!=-1)
{
if (mArg!=-1)
throw std::runtime_error (
"magic effect can't have both a skill and an attribute argument");
mArg = effect.attribute;
}
}
bool operator< (const EffectKey& left, const EffectKey& right)
{
if (left.mId<right.mId)
return true;
if (left.mId>right.mId)
return false;
return left.mArg<right.mArg;
}
EffectParam::EffectParam() : mMagnitude (0) {}
EffectParam& EffectParam::operator+= (const EffectParam& param)
{
mMagnitude += param.mMagnitude;
return *this;
}
EffectParam& EffectParam::operator-= (const EffectParam& param)
{
mMagnitude -= param.mMagnitude;
return *this;
}
void MagicEffects::add (const EffectKey& key, const EffectParam& param)
{
Collection::iterator iter = mCollection.find (key);
if (iter==mCollection.end())
{
mCollection.insert (std::make_pair (key, param));
}
else
{
iter->second += param;
}
}
EffectParam MagicEffects::get (const EffectKey& key) const
{
Collection::const_iterator iter = mCollection.find (key);
if (iter==mCollection.end())
{
return EffectParam();
}
else
{
return iter->second;
}
}
MagicEffects MagicEffects::diff (const MagicEffects& prev, const MagicEffects& now)
{
MagicEffects result;
// adding/changing
for (Collection::const_iterator iter (now.Begin()); iter!=now.End(); ++iter)
{
Collection::const_iterator other = prev.mCollection.find (iter->first);
if (other==prev.End())
{
// adding
result.add (iter->first, iter->second);
}
else
{
// changing
result.add (iter->first, iter->second - other->second);
}
}
// removing
for (Collection::const_iterator iter (prev.Begin()); iter!=prev.End(); ++iter)
{
Collection::const_iterator other = now.mCollection.find (iter->first);
if (other==prev.End())
{
result.add (iter->first, EffectParam() - iter->second);
}
}
return result;
}
}

View file

@ -0,0 +1,77 @@
#ifndef GAME_MWMECHANICS_MAGICEFFECTS_H
#define GAME_MWMECHANICS_MAGICEFFECTS_H
#include <map>
namespace ESM
{
struct ENAMstruct;
}
namespace MWMechanics
{
struct EffectKey
{
int mId;
int mArg; // skill or ability
EffectKey();
EffectKey (int id, int arg = -1) : mId (id), mArg (arg) {}
EffectKey (const ESM::ENAMstruct& effect);
};
bool operator< (const EffectKey& left, const EffectKey& right);
struct EffectParam
{
int mMagnitude;
EffectParam();
EffectParam& operator+= (const EffectParam& param);
EffectParam& operator-= (const EffectParam& param);
};
inline EffectParam operator+ (const EffectParam& left, const EffectParam& right)
{
EffectParam param (left);
return param += right;
}
inline EffectParam operator- (const EffectParam& left, const EffectParam& right)
{
EffectParam param (left);
return param -= right;
}
/// \brief Effects currently affecting a NPC or creature
class MagicEffects
{
public:
typedef std::map<EffectKey, EffectParam> Collection;
private:
Collection mCollection;
public:
Collection::const_iterator Begin() const { return mCollection.begin(); }
Collection::const_iterator End() const { return mCollection.end(); }
void add (const EffectKey& key, const EffectParam& param);
EffectParam get (const EffectKey& key) const;
///< This function can safely be used for keys that are not present.
static MagicEffects diff (const MagicEffects& prev, const MagicEffects& now);
///< Return changes from \a prev to \a now.
};
}
#endif

View file

@ -22,63 +22,123 @@ namespace MWMechanics
// reset
creatureStats.mLevel = player->npdt52.level;
creatureStats.mAbilities.clear();
creatureStats.mMagicEffects = MagicEffects();
for (int i=0; i<27; ++i)
npcStats.mSkill[i].setBase (player->npdt52.skills[i]);
// race
const ESM::Race *race =
mEnvironment.mWorld->getStore().races.find (mEnvironment.mWorld->getPlayerPos().getRace());
bool male = mEnvironment.mWorld->getPlayerPos().isMale();
for (int i=0; i<8; ++i)
if (mRaceSelected)
{
const ESM::Race::MaleFemale *attribute = 0;
switch (i)
const ESM::Race *race =
mEnvironment.mWorld->getStore().races.find (
mEnvironment.mWorld->getPlayerPos().getRace());
bool male = mEnvironment.mWorld->getPlayerPos().isMale();
for (int i=0; i<8; ++i)
{
case 0: attribute = &race->data.strength; break;
case 1: attribute = &race->data.intelligence; break;
case 2: attribute = &race->data.willpower; break;
case 3: attribute = &race->data.agility; break;
case 4: attribute = &race->data.speed; break;
case 5: attribute = &race->data.endurance; break;
case 6: attribute = &race->data.personality; break;
case 7: attribute = &race->data.luck; break;
const ESM::Race::MaleFemale *attribute = 0;
switch (i)
{
case 0: attribute = &race->data.strength; break;
case 1: attribute = &race->data.intelligence; break;
case 2: attribute = &race->data.willpower; break;
case 3: attribute = &race->data.agility; break;
case 4: attribute = &race->data.speed; break;
case 5: attribute = &race->data.endurance; break;
case 6: attribute = &race->data.personality; break;
case 7: attribute = &race->data.luck; break;
}
creatureStats.mAttributes[i].setBase (
static_cast<int> (male ? attribute->male : attribute->female));
}
creatureStats.mAttributes[i].setBase (
static_cast<int> (male ? attribute->male : attribute->female));
}
for (int i=0; i<7; ++i)
{
int index = race->data.bonus[i].skill;
if (index>=0 && index<27)
for (int i=0; i<7; ++i)
{
npcStats.mSkill[i].setBase (
npcStats.mSkill[i].getBase() + race->data.bonus[i].bonus);
int index = race->data.bonus[i].skill;
if (index>=0 && index<27)
{
npcStats.mSkill[index].setBase (
npcStats.mSkill[index].getBase() + race->data.bonus[i].bonus);
}
}
for (std::vector<std::string>::const_iterator iter (race->powers.list.begin());
iter!=race->powers.list.end(); ++iter)
{
insertSpell (*iter, ptr);
}
}
// birthsign
// class
const ESM::Class& class_ = mEnvironment.mWorld->getPlayerPos().getClass();
for (int i=0; i<2; ++i)
if (!mEnvironment.mWorld->getPlayerPos().getBirthsign().empty())
{
int attribute = class_.data.attribute[i];
if (attribute>=0 && attribute<8)
const ESM::BirthSign *sign =
mEnvironment.mWorld->getStore().birthSigns.find (
mEnvironment.mWorld->getPlayerPos().getBirthsign());
for (std::vector<std::string>::const_iterator iter (sign->powers.list.begin());
iter!=sign->powers.list.end(); ++iter)
{
creatureStats.mAttributes[attribute].setBase (
creatureStats.mAttributes[attribute].getBase() + 10);
insertSpell (*iter, ptr);
}
}
// class
if (mClassSelected)
{
const ESM::Class& class_ = mEnvironment.mWorld->getPlayerPos().getClass();
for (int i=0; i<2; ++i)
{
int attribute = class_.data.attribute[i];
if (attribute>=0 && attribute<8)
{
creatureStats.mAttributes[attribute].setBase (
creatureStats.mAttributes[attribute].getBase() + 10);
}
}
for (int i=0; i<2; ++i)
{
int bonus = i==0 ? 10 : 25;
for (int i2=0; i2<5; ++i2)
{
int index = class_.data.skills[i2][i];
if (index>=0 && index<27)
{
npcStats.mSkill[index].setBase (
npcStats.mSkill[index].getBase() + bonus);
}
}
}
typedef ESMS::IndexListT<ESM::Skill>::MapType ContainerType;
const ContainerType& skills = mEnvironment.mWorld->getStore().skills.list;
for (ContainerType::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
{
if (iter->second.data.specialization==class_.data.specialization)
{
int index = iter->first;
if (index>=0 && index<27)
{
npcStats.mSkill[index].setBase (
npcStats.mSkill[index].getBase() + 5);
}
}
}
}
// magic effects
adjustMagicEffects (ptr);
// calculate dynamic stats
int strength = creatureStats.mAttributes[0].getBase();
@ -87,17 +147,81 @@ namespace MWMechanics
int agility = creatureStats.mAttributes[3].getBase();
int endurance = creatureStats.mAttributes[5].getBase();
double magickaFactor = creatureStats.mMagicEffects.get (EffectKey (84)).mMagnitude*0.1 + 0.5;
creatureStats.mDynamic[0].setBase (static_cast<int> (0.5 * (strength + endurance)));
// TODO: calculate factor
creatureStats.mDynamic[1].setBase (static_cast<int> (intelligence + 1 * intelligence));
creatureStats.mDynamic[1].setBase (static_cast<int> (intelligence +
magickaFactor * intelligence));
creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance);
for (int i=0; i<3; ++i)
creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified());
}
void MechanicsManager::insertSpell (const std::string& id, MWWorld::Ptr& creature)
{
MWMechanics::CreatureStats& creatureStats =
MWWorld::Class::get (creature).getCreatureStats (creature);
const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (id);
switch (spell->data.type)
{
case ESM::Spell::ST_Ability:
if (creatureStats.mAbilities.find (id)==creatureStats.mAbilities.end())
{
creatureStats.mAbilities.insert (id);
}
break;
// TODO ST_SPELL, ST_Blight, ST_Disease, ST_Curse, ST_Power
default:
std::cout
<< "adding unsupported spell type (" << spell->data.type
<< ") to creature: " << id << std::endl;
}
}
void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature)
{
MWMechanics::CreatureStats& creatureStats =
MWWorld::Class::get (creature).getCreatureStats (creature);
MagicEffects now;
for (std::set<std::string>::const_iterator iter (creatureStats.mAbilities.begin());
iter!=creatureStats.mAbilities.end(); ++iter)
{
const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (*iter);
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->effects.list.begin();
iter!=spell->effects.list.end(); ++iter)
{
if (iter->range==0) // self
{
EffectParam param;
param.mMagnitude = iter->magnMax; // TODO calculate magnitude
now.add (EffectKey (*iter), param);
}
}
}
// TODO add effects from other spell types, active spells and equipment
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now);
creatureStats.mMagicEffects = now;
// TODO apply diff to other stats
}
MechanicsManager::MechanicsManager (MWWorld::Environment& environment)
: mEnvironment (environment), mUpdatePlayer (true)
: mEnvironment (environment), mUpdatePlayer (true), mClassSelected (false),
mRaceSelected (false)
{
buildPlayer();
}
@ -237,6 +361,7 @@ namespace MWMechanics
{
mEnvironment.mWorld->getPlayerPos().setGender (male);
mEnvironment.mWorld->getPlayerPos().setRace (race);
mRaceSelected = true;
buildPlayer();
mUpdatePlayer = true;
}
@ -250,6 +375,7 @@ namespace MWMechanics
void MechanicsManager::setPlayerClass (const std::string& id)
{
mEnvironment.mWorld->getPlayerPos().setClass (*mEnvironment.mWorld->getStore().classes.find (id));
mClassSelected = true;
buildPlayer();
mUpdatePlayer = true;
}
@ -257,6 +383,7 @@ namespace MWMechanics
void MechanicsManager::setPlayerClass (const ESM::Class& class_)
{
mEnvironment.mWorld->getPlayerPos().setClass (class_);
mClassSelected = true;
buildPlayer();
mUpdatePlayer = true;
}

View file

@ -23,11 +23,17 @@ namespace MWMechanics
CreatureStats mWatchedCreature;
NpcStats mWatchedNpc;
bool mUpdatePlayer;
bool mClassSelected;
bool mRaceSelected;
void buildPlayer();
///< build player according to stored class/race/birthsign information. Will
/// default to the values of the ESM::NPC object, if no explicit information is given.
void insertSpell (const std::string& id, MWWorld::Ptr& creature);
void adjustMagicEffects (MWWorld::Ptr& creature);
public:
MechanicsManager (MWWorld::Environment& environment);

View file

@ -13,7 +13,7 @@ namespace Interpreter
namespace MWScript
{
/// \brief stats-related script functionality (creatures and NPCs)
/// \brief Container-related script functionality (chests, NPCs, creatures)
namespace Container
{
void registerExtensions (Compiler::Extensions& extensions);

View file

@ -95,4 +95,10 @@ op 0x2000085-0x200008b: Disable Controls
op 0x200008c: Unlock
op 0x200008d: Unlock, explicit reference
op 0x200008e: COE
opcodes 0x200008f-0x3ffffff unused
op 0x200008e-0x20000a8: GetSkill
op 0x20000a9-0x20000c3: GetSkill, explicit reference
op 0x20000c4-0x20000de: SetSkill
op 0x20000df-0x20000f9: SetSkill, explicit reference
op 0x20000fa-0x2000114: ModSkill
op 0x2000115-0x200012f: ModSKill, explicit reference
opcodes 0x2000130-0x3ffffff unused

View file

@ -27,7 +27,7 @@ namespace Interpreter
}
namespace MWScript
{
{
class ScriptManager
{
Compiler::StreamErrorHandler mErrorHandler;
@ -35,19 +35,21 @@ namespace MWScript
bool mVerbose;
Compiler::Context& mCompilerContext;
Compiler::FileParser mParser;
std::map<std::string, std::vector<Interpreter::Type_Code> > mScripts;
bool compile (const std::string& name);
public:
ScriptManager (const ESMS::ESMStore& store, bool verbose,
Compiler::Context& compilerContext);
void run (const std::string& name, Interpreter::Context& interpreterContext);
///< Run the script with the given name (compile first, if not compiled yet)
bool compile (const std::string& name);
///< Compile script with the given namen
/// \return Success?
};
};
#endif

View file

@ -468,6 +468,160 @@ namespace MWScript
}
};
class OpGetSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpGetSkill (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
MWWorld::Ptr ptr = context.getReference();
Interpreter::Type_Integer value =
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
getModified();
runtime.push (value);
}
};
class OpGetSkillExplicit : public Interpreter::Opcode0
{
int mIndex;
public:
OpGetSkillExplicit (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
Interpreter::Type_Integer value =
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
getModified();
runtime.push (value);
}
};
class OpSetSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpSetSkill (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWWorld::Ptr ptr = context.getReference();
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
setModified (value, 0);
}
};
class OpSetSkillExplicit : public Interpreter::Opcode0
{
int mIndex;
public:
OpSetSkillExplicit (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
setModified (value, 0);
}
};
class OpModSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpModSkill (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWWorld::Ptr ptr = context.getReference();
value += MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
getModified();
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
setModified (value, 0, 100);
}
};
class OpModSkillExplicit : public Interpreter::Opcode0
{
int mIndex;
public:
OpModSkillExplicit (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
value +=
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
getModified();
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
setModified (value, 0, 100);
}
};
const int numberOfAttributes = 8;
const int opcodeGetAttribute = 0x2000027;
@ -490,6 +644,15 @@ namespace MWScript
const int opcodeGetDynamicGetRatio = 0x200006f;
const int opcodeGetDynamicGetRatioExplicit = 0x2000072;
const int numberOfSkills = 27;
const int opcodeGetSkill = 0x200008e;
const int opcodeGetSkillExplicit = 0x20000a9;
const int opcodeSetSkill = 0x20000c4;
const int opcodeSetSkillExplicit = 0x20000df;
const int opcodeModSkill = 0x20000fa;
const int opcodeModSkillExplicit = 0x2000115;
void registerExtensions (Compiler::Extensions& extensions)
{
static const char *attributes[numberOfAttributes] =
@ -503,6 +666,16 @@ namespace MWScript
"health", "magicka", "fatigue"
};
static const char *skills[numberOfSkills] =
{
"block", "armorer", "mediumarmor", "heavyarmor", "bluntweapon",
"longblade", "axe", "spear", "athletics", "enchant", "destruction",
"alteration", "illusion", "conjuration", "mysticism",
"restoration", "alchemy", "unarmored", "security", "sneak",
"acrobatics", "lightarmor", "shortblade", "marksman",
"merchantile", "speechcraft", "handtohand"
};
std::string get ("get");
std::string set ("set");
std::string mod ("mod");
@ -537,7 +710,18 @@ namespace MWScript
extensions.registerFunction (get + dynamics[i] + getRatio, 'f', "",
opcodeGetDynamicGetRatio+i, opcodeGetDynamicGetRatioExplicit+i);
}
for (int i=0; i<numberOfSkills; ++i)
{
extensions.registerFunction (get + skills[i], 'l', "",
opcodeGetSkill+i, opcodeGetSkillExplicit+i);
extensions.registerInstruction (set + skills[i], "l",
opcodeSetSkill+i, opcodeSetSkillExplicit+i);
extensions.registerInstruction (mod + skills[i], "l",
opcodeModSkill+i, opcodeModSkillExplicit+i);
}
}
@ -581,6 +765,18 @@ namespace MWScript
interpreter.installSegment5 (opcodeGetDynamicGetRatioExplicit+i,
new OpGetDynamicGetRatioExplicit (i));
}
for (int i=0; i<numberOfSkills; ++i)
{
interpreter.installSegment5 (opcodeGetSkill+i, new OpGetSkill (i));
interpreter.installSegment5 (opcodeGetSkillExplicit+i, new OpGetSkillExplicit (i));
interpreter.installSegment5 (opcodeSetSkill+i, new OpSetSkill (i));
interpreter.installSegment5 (opcodeSetSkillExplicit+i, new OpSetSkillExplicit (i));
interpreter.installSegment5 (opcodeModSkill+i, new OpModSkill (i));
interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkillExplicit (i));
}
}
}
}