mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 23:23:52 +00:00
Implement leveled list script functions (Fixes #1546)
This commit is contained in:
parent
d642512f71
commit
31d28e727f
11 changed files with 182 additions and 7 deletions
|
@ -40,6 +40,8 @@ namespace ESM
|
||||||
struct Enchantment;
|
struct Enchantment;
|
||||||
struct Book;
|
struct Book;
|
||||||
struct EffectList;
|
struct EffectList;
|
||||||
|
struct CreatureLevList;
|
||||||
|
struct ItemLevList;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -359,6 +361,14 @@ namespace MWBase
|
||||||
///< Create a new record (of type book) in the ESM store.
|
///< Create a new record (of type book) in the ESM store.
|
||||||
/// \return pointer to created record
|
/// \return pointer to created record
|
||||||
|
|
||||||
|
virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record) = 0;
|
||||||
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
|
/// \return pointer to created record
|
||||||
|
|
||||||
|
virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record) = 0;
|
||||||
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
|
/// \return pointer to created record
|
||||||
|
|
||||||
virtual void update (float duration, bool paused) = 0;
|
virtual void update (float duration, bool paused) = 0;
|
||||||
|
|
||||||
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0;
|
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0;
|
||||||
|
|
|
@ -438,5 +438,9 @@ op 0x20002f7: PCForce3rdPerson
|
||||||
op 0x20002f8: PCGet3rdPerson
|
op 0x20002f8: PCGet3rdPerson
|
||||||
op 0x20002f9: HitAttemptOnMe
|
op 0x20002f9: HitAttemptOnMe
|
||||||
op 0x20002fa: HitAttemptOnMe, explicit
|
op 0x20002fa: HitAttemptOnMe, explicit
|
||||||
|
op 0x20002fb: AddToLevCreature
|
||||||
|
op 0x20002fc: RemoveFromLevCreature
|
||||||
|
op 0x20002fd: AddToLevItem
|
||||||
|
op 0x20002fe: RemoveFromLevItem
|
||||||
|
|
||||||
opcodes 0x20002fb-0x3ffffff unused
|
opcodes 0x20002ff-0x3ffffff unused
|
||||||
|
|
|
@ -31,6 +31,42 @@
|
||||||
#include "interpretercontext.hpp"
|
#include "interpretercontext.hpp"
|
||||||
#include "ref.hpp"
|
#include "ref.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
void addToLevList(ESM::LeveledListBase* list, const std::string& itemId, int level)
|
||||||
|
{
|
||||||
|
for (std::vector<ESM::LeveledListBase::LevelItem>::iterator it = list->mList.begin(); it != list->mList.end();)
|
||||||
|
{
|
||||||
|
if (it->mLevel == level && itemId == it->mId)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM::LeveledListBase::LevelItem item;
|
||||||
|
item.mId = itemId;
|
||||||
|
item.mLevel = level;
|
||||||
|
list->mList.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeFromLevList(ESM::LeveledListBase* list, const std::string& itemId, int level)
|
||||||
|
{
|
||||||
|
// level of -1 removes all items with that itemId
|
||||||
|
for (std::vector<ESM::LeveledListBase::LevelItem>::iterator it = list->mList.begin(); it != list->mList.end();)
|
||||||
|
{
|
||||||
|
if (level != -1 && it->mLevel != level)
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Misc::StringUtils::ciEqual(itemId, it->mId))
|
||||||
|
it = list->mList.erase(it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
namespace Misc
|
namespace Misc
|
||||||
|
@ -1032,6 +1068,78 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OpAddToLevCreature : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void execute(Interpreter::Runtime &runtime)
|
||||||
|
{
|
||||||
|
const std::string& levId = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
const std::string& creatureId = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
int level = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
ESM::CreatureLevList listCopy = *MWBase::Environment::get().getWorld()->getStore().get<ESM::CreatureLevList>().find(levId);
|
||||||
|
addToLevList(&listCopy, creatureId, level);
|
||||||
|
MWBase::Environment::get().getWorld()->createOverrideRecord(listCopy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpRemoveFromLevCreature : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void execute(Interpreter::Runtime &runtime)
|
||||||
|
{
|
||||||
|
const std::string& levId = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
const std::string& creatureId = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
int level = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
ESM::CreatureLevList listCopy = *MWBase::Environment::get().getWorld()->getStore().get<ESM::CreatureLevList>().find(levId);
|
||||||
|
removeFromLevList(&listCopy, creatureId, level);
|
||||||
|
MWBase::Environment::get().getWorld()->createOverrideRecord(listCopy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpAddToLevItem : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void execute(Interpreter::Runtime &runtime)
|
||||||
|
{
|
||||||
|
const std::string& levId = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
const std::string& itemId = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
int level = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
ESM::ItemLevList listCopy = *MWBase::Environment::get().getWorld()->getStore().get<ESM::ItemLevList>().find(levId);
|
||||||
|
addToLevList(&listCopy, itemId, level);
|
||||||
|
MWBase::Environment::get().getWorld()->createOverrideRecord(listCopy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpRemoveFromLevItem : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void execute(Interpreter::Runtime &runtime)
|
||||||
|
{
|
||||||
|
const std::string& levId = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
const std::string& itemId = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
int level = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
ESM::ItemLevList listCopy = *MWBase::Environment::get().getWorld()->getStore().get<ESM::ItemLevList>().find(levId);
|
||||||
|
removeFromLevList(&listCopy, itemId, level);
|
||||||
|
MWBase::Environment::get().getWorld()->createOverrideRecord(listCopy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
|
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
|
||||||
|
@ -1121,6 +1229,10 @@ namespace MWScript
|
||||||
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling);
|
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling);
|
||||||
interpreter.installSegment5 (Compiler::Misc::opcodeBetaComment, new OpBetaComment<ImplicitRef>);
|
interpreter.installSegment5 (Compiler::Misc::opcodeBetaComment, new OpBetaComment<ImplicitRef>);
|
||||||
interpreter.installSegment5 (Compiler::Misc::opcodeBetaCommentExplicit, new OpBetaComment<ExplicitRef>);
|
interpreter.installSegment5 (Compiler::Misc::opcodeBetaCommentExplicit, new OpBetaComment<ExplicitRef>);
|
||||||
|
interpreter.installSegment5 (Compiler::Misc::opcodeAddToLevCreature, new OpAddToLevCreature);
|
||||||
|
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveFromLevCreature, new OpRemoveFromLevCreature);
|
||||||
|
interpreter.installSegment5 (Compiler::Misc::opcodeAddToLevItem, new OpAddToLevItem);
|
||||||
|
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveFromLevItem, new OpRemoveFromLevItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,6 +352,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
|
||||||
case ESM::REC_PROJ:
|
case ESM::REC_PROJ:
|
||||||
case ESM::REC_MPRJ:
|
case ESM::REC_MPRJ:
|
||||||
case ESM::REC_ENAB:
|
case ESM::REC_ENAB:
|
||||||
|
case ESM::REC_LEVC:
|
||||||
|
case ESM::REC_LEVI:
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap);
|
MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -149,7 +149,9 @@ void ESMStore::setUp()
|
||||||
+mEnchants.getDynamicSize()
|
+mEnchants.getDynamicSize()
|
||||||
+mNpcs.getDynamicSize()
|
+mNpcs.getDynamicSize()
|
||||||
+mSpells.getDynamicSize()
|
+mSpells.getDynamicSize()
|
||||||
+mWeapons.getDynamicSize();
|
+mWeapons.getDynamicSize()
|
||||||
|
+mCreatureLists.getDynamicSize()
|
||||||
|
+mItemLists.getDynamicSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESMStore::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
|
void ESMStore::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||||
|
@ -170,6 +172,8 @@ void ESMStore::setUp()
|
||||||
mSpells.write (writer, progress);
|
mSpells.write (writer, progress);
|
||||||
mWeapons.write (writer, progress);
|
mWeapons.write (writer, progress);
|
||||||
mNpcs.write (writer, progress);
|
mNpcs.write (writer, progress);
|
||||||
|
mItemLists.write (writer, progress);
|
||||||
|
mCreatureLists.write (writer, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type)
|
bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||||
|
@ -185,6 +189,8 @@ void ESMStore::setUp()
|
||||||
case ESM::REC_SPEL:
|
case ESM::REC_SPEL:
|
||||||
case ESM::REC_WEAP:
|
case ESM::REC_WEAP:
|
||||||
case ESM::REC_NPC_:
|
case ESM::REC_NPC_:
|
||||||
|
case ESM::REC_LEVI:
|
||||||
|
case ESM::REC_LEVC:
|
||||||
|
|
||||||
mStores[type]->read (reader);
|
mStores[type]->read (reader);
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,7 @@ namespace MWWorld
|
||||||
throw std::runtime_error("Storage for this type not exist");
|
throw std::runtime_error("Storage for this type not exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert a custom record (i.e. with a generated ID that will not clash will pre-existing records)
|
||||||
template <class T>
|
template <class T>
|
||||||
const T *insert(const T &x) {
|
const T *insert(const T &x) {
|
||||||
std::ostringstream id;
|
std::ostringstream id;
|
||||||
|
@ -191,6 +192,20 @@ namespace MWWorld
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert a record with set ID, and allow it to override a pre-existing static record.
|
||||||
|
template <class T>
|
||||||
|
const T *overrideRecord(const T &x) {
|
||||||
|
Store<T> &store = const_cast<Store<T> &>(get<T>());
|
||||||
|
|
||||||
|
T *ptr = store.insert(x);
|
||||||
|
for (iterator it = mStores.begin(); it != mStores.end(); ++it) {
|
||||||
|
if (it->second == &store) {
|
||||||
|
mIds[ptr->mId] = it->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
const T *insertStatic(const T &x) {
|
const T *insertStatic(const T &x) {
|
||||||
std::ostringstream id;
|
std::ostringstream id;
|
||||||
|
|
|
@ -145,17 +145,17 @@ namespace MWWorld
|
||||||
T item;
|
T item;
|
||||||
item.mId = Misc::StringUtils::lowerCase(id);
|
item.mId = Misc::StringUtils::lowerCase(id);
|
||||||
|
|
||||||
|
typename Dynamic::const_iterator dit = mDynamic.find(item.mId);
|
||||||
|
if (dit != mDynamic.end()) {
|
||||||
|
return &dit->second;
|
||||||
|
}
|
||||||
|
|
||||||
typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId);
|
typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId);
|
||||||
|
|
||||||
if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
|
if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
|
||||||
return &(it->second);
|
return &(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
typename Dynamic::const_iterator dit = mDynamic.find(item.mId);
|
|
||||||
if (dit != mDynamic.end()) {
|
|
||||||
return &dit->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1490,6 +1490,16 @@ namespace MWWorld
|
||||||
return mStore.insert(record);
|
return mStore.insert(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ESM::CreatureLevList *World::createOverrideRecord(const ESM::CreatureLevList &record)
|
||||||
|
{
|
||||||
|
return mStore.overrideRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ESM::ItemLevList *World::createOverrideRecord(const ESM::ItemLevList &record)
|
||||||
|
{
|
||||||
|
return mStore.overrideRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
const ESM::NPC *World::createRecord(const ESM::NPC &record)
|
const ESM::NPC *World::createRecord(const ESM::NPC &record)
|
||||||
{
|
{
|
||||||
bool update = false;
|
bool update = false;
|
||||||
|
|
|
@ -420,6 +420,14 @@ namespace MWWorld
|
||||||
///< Create a new record (of type book) in the ESM store.
|
///< Create a new record (of type book) in the ESM store.
|
||||||
/// \return pointer to created record
|
/// \return pointer to created record
|
||||||
|
|
||||||
|
virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record);
|
||||||
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
|
/// \return pointer to created record
|
||||||
|
|
||||||
|
virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record);
|
||||||
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
|
/// \return pointer to created record
|
||||||
|
|
||||||
virtual void update (float duration, bool paused);
|
virtual void update (float duration, bool paused);
|
||||||
|
|
||||||
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount);
|
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount);
|
||||||
|
|
|
@ -308,6 +308,10 @@ namespace Compiler
|
||||||
extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling);
|
extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling);
|
||||||
extensions.registerInstruction ("betacomment", "S", opcodeBetaComment, opcodeBetaCommentExplicit);
|
extensions.registerInstruction ("betacomment", "S", opcodeBetaComment, opcodeBetaCommentExplicit);
|
||||||
extensions.registerInstruction ("bc", "S", opcodeBetaComment, opcodeBetaCommentExplicit);
|
extensions.registerInstruction ("bc", "S", opcodeBetaComment, opcodeBetaCommentExplicit);
|
||||||
|
extensions.registerInstruction ("addtolevcreature", "ccl", opcodeAddToLevCreature);
|
||||||
|
extensions.registerInstruction ("removefromlevcreature", "ccl", opcodeRemoveFromLevCreature);
|
||||||
|
extensions.registerInstruction ("addtolevitem", "ccl", opcodeAddToLevItem);
|
||||||
|
extensions.registerInstruction ("removefromlevitem", "ccl", opcodeRemoveFromLevItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -284,6 +284,10 @@ namespace Compiler
|
||||||
const int opcodeExplodeSpellExplicit = 0x200022a;
|
const int opcodeExplodeSpellExplicit = 0x200022a;
|
||||||
const int opcodeGetPcInJail = 0x200023e;
|
const int opcodeGetPcInJail = 0x200023e;
|
||||||
const int opcodeGetPcTraveling = 0x200023f;
|
const int opcodeGetPcTraveling = 0x200023f;
|
||||||
|
const int opcodeAddToLevCreature = 0x20002fb;
|
||||||
|
const int opcodeRemoveFromLevCreature = 0x20002fc;
|
||||||
|
const int opcodeAddToLevItem = 0x20002fd;
|
||||||
|
const int opcodeRemoveFromLevItem = 0x20002fe;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Sky
|
namespace Sky
|
||||||
|
|
Loading…
Reference in a new issue